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]);
}
}