题目大意:给一个正整数N,每次可以在不超过N的素数中随机选择一个P,如果P是N的约数,则把N变成N/p,否则N不变,问平均情况下需要多少次随机选择,才能把N变成1?

分析:根据数学期望的线性和全期望公式可以为每个状态列出一个方程,例如: f(x)=1+f(6)*1/3+f(3)*1/3+f(2)*1/3

等式右边的最前面的“1”是指第一次转移,而后面的几项是后续的转移,用全期望公式展开,一般地,设不超过x的素数有p个,其中有g个是x的因子,则

f(x)=1+f(x)*(1-g/p)+Σf(x/y)/p

边界f(1)=0。移项后整理得

f(x)=(Σf(x/y)+p)/g

因为x/y<x,可以用记忆化搜索的方式计算f(x)。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std; const int Max=;
int prime[],Num;
bool flag[Max],vis[Max];
double f[Max]; void Init()
{
int i,j;
Num=;
for(i=;i<Max;i++)
{
if(flag[i]) prime[Num++]=i;
for(j=;j<Num && i*prime[j]<Max;j++)
{
flag[i*prime[j]]=false;
if(i%prime[j]==) break;
}
}
} double dp(int x)
{
if(x==) return 0.0;
if(vis[x]) return f[x];
vis[x]=true;
double sum=;
int p=,g=;
for(int i=;i<Num && prime[i]<=x;i++)
{
p++;
if(x%prime[i]==)
{
g++;
sum+=dp(x/prime[i]);
}
}
sum=(sum+p)/g;
return f[x]=sum;
} int main()
{
memset(flag,true,sizeof(flag));
memset(vis,false,sizeof(vis));
memset(f,0.0,sizeof(f));
Init();
int t,i,n;
scanf("%d",&t);
for(i=;i<=t;i++)
{
scanf("%d",&n);
printf("Case %d: %.10lf\n",i,dp(n));
}
return ;
}

最新文章

  1. Vue插件开发入门
  2. Win7 下安装VirtualBox 没有Ubuntu 64bit 选项问题
  3. EF4.1使用
  4. Oracle 安装后关于用户
  5. 编译Ansj之Solr插件
  6. UNIX环境高级编程笔记之进程环境
  7. 对所有CPU寄存器的简述(16位CPU14个,32位CPU16个)
  8. 1471. Tree(LCA)
  9. java.sql.SQLException: Can not issue executeUpdate() for SELECTs
  10. jQuery插件实现左右无缝轮播
  11. FFmpeg源代码简单分析:av_find_decoder()和av_find_encoder()
  12. 分门别类总结Java中的各种锁,让你彻底记住
  13. Linux 操作系统目录结构
  14. 消息队列工具类(MSMQ)
  15. LeetCode--No.015 3Sum
  16. [转帖] iptables之四表五链
  17. python之tkinter使用-滚动条
  18. Java对象池
  19. JSON.stringify报cyclic object value错误
  20. COM结构化存储中存储对象或者流对象的命名规则

热门文章

  1. codevs 2915 期末考试
  2. 系统相册中获取gif图片 保证取到的图片不会改变
  3. ES6新增Map、Set和iterable
  4. java面试基础篇(三)
  5. vs code背景图片的设置
  6. 编写个makefile文件测试patsubst 的作用
  7. stm32开发套件选择——LL SPL HAL Snippets的应用范围
  8. python基础——9(迭代器、生成器)
  9. 利用Vert.x构建简单的API 服务、分布式服务
  10. 关于awk中NR、FNR、NF、$NF、FS、OFS的说明