https://cn.vjudge.net/problem/LightOJ-1038
Rimi learned a new thing about integers, which is - any positive integer greater than 1 can be divided by its divisors. So, he is now playing with this property. He selects a number N. And he calls this D.
In each turn he randomly chooses a divisor of D (1 to D). Then he divides D by the number to obtain new D. He repeats this procedure until D becomes 1. What is the expected number of moves required for N to become 1.
Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.
Each case begins with an integer N (1 ≤ N ≤ 105).
Output
For each case of input you have to print the case number and the expected value. Errors less than 10-6 will be ignored.
Sample Input
3
1
2
50
Case 1: 0
Case 2: 2.00
Case 3: 3.0333333333
题意:给你一个n,n可以变一次变成他的某一个约数,然后在变成他的某个约数,直到变成1,求n变为1的期望次数?
思路:dp[50]=(dp[1]+1)/6+(dp[2]+1)/6+(dp[5]+1)/6+(dp[10]+1)/6+(dp[25]+1)/6+(dp[50]+1)/6;
怎么枚举每个数字的因子呢,可以用(素数)筛法处理。
遍历到i时,将dp[i]求出,然后将dp[i]的值加入到他的 dp[i的倍数] 中,那么当i=50时,怎么求出dp[50]呢。
当前的dp[50]中的值存的是dp[1]+dp[2]+dp[5]+dp[10]+dp[25],在开一个数组a[i]表示当前的dp[i]中装了多少个数字。及a[50]=5;
假设x为要求出的dp[50]的最终概率, 设sum(及当前dp[50]中存的数字)=dp[1]+dp[2]+dp[5]+dp[10]+dp[25],
dp[50]=(dp[1]+1)/6+(dp[2]+1)/6+(dp[5]+1)/6+(dp[10]+1)/6+(dp[25]+1)/6+(dp[50]+1)/6;
那么等式变为x=(dp[1]+dp[2]+dp[5]+dp[10]+dp[25]+x+a[i]+1)/(a[i]+1);
(a[i]+1)*x=(sum+x+a[i]+1)
a[i]*x=(sum+a[i]+1)
x=(sum+a[i]+1)/a[i];
sum的值也就是当前dp[i]中存的值了;所以dp[i]=(dp[i]+a[i]+1)/a[i];( i>1时成立)
代码:(20ms)
#include <iostream> #include <stdio.h> #include <string.h> #include <string> #include <map> #include <queue> #include <math.h> #include <time.h> #include <algorithm> #define mem(a,b) memset(a,b,sizeof a) #define LL long long #define inf 0x3f3f3f3f #define y1 ctx_y1 #define x1 ctx_x1 const LL mod=1e9+7; const int N=1e5+10; const int M=1e5; using namespace std; double dp[N]; int a[N]; int main() { mem(dp,0); mem(a,0); dp[1]=0; for(int i=1;i<=100000;i++) { if(i!=1) dp[i]=(a[i]+1+dp[i])/a[i]; for(int j=i*2;j<=100000;j+=i) { dp[j]+=dp[i]; a[j]++; } } int t,cas=1; scanf("%d",&t); while(t--) { int n; scanf("%d",&n); printf("Case %d: %.7f\n",cas++,dp[n]); } }