题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20869
【思路】
DP+期望。
设f[x]表示从x转移到1的期望操作次数,则有:
f[x]=1+f[x]*(1-g[x]/p[x])+sigma(f[x][y])/p[x]
进一步为:
f[x]=(sigma(f[x/y])+p[x])/g[x]
其中p[x]表示1..x的素数个数,p[x]表示素数中可以整除x的个数。
保留vis可以节约时间。
【代码】
1 #include<cstdio> 2 #include<cmath> 3 #include<vector> 4 #include<cstring> 5 using namespace std; 6 7 typedef long long ll; 8 const int N = 1e6+10; 9 10 double f[N]; 11 vector<int> ps; 12 int n,vis[N],isp[N]; 13 14 void get_primes() { 15 memset(isp,0,sizeof(isp)); 16 for(int i=2;i<=N;i++) if(!isp[i]) { 17 ps.push_back(i); 18 if((ll)i*i<=(ll)N)for(int j=i*i;j<=N;j+=i) isp[j]=1; 19 } 20 } 21 22 double dp(int x) { 23 if(x==1) return 0; 24 if(vis[x]) return f[x]; 25 vis[x]=1; 26 f[x]=0.0; int g=0,p=0; 27 for(int i=0;i<ps.size() && ps[i]<=x;i++) { 28 int y=ps[i]; p++; 29 if(x%y==0) g++ , f[x]+=dp(x/y); 30 } 31 f[x]=(f[x]+p)/g; 32 return f[x]; 33 } 34 35 int main() { 36 get_primes(); 37 int T,kase=0; 38 scanf("%d",&T); 39 while(T--) { 40 scanf("%d",&n); 41 printf("Case %d: %.10lf\n",++kase,dp(n)); 42 } 43 return 0; 44 }
时间: 2024-10-06 07:48:26