LightOJ 1038 Race to 1 again 期望+概率dp

来源:互联网 发布:mac推出u盘快捷键 编辑:程序博客网 时间:2024/05/16 17:15
/*    题目描述:给定正整数n,每次任意选择n的一个因子并除掉,问平均一共要除多少次能把n变成1        思路:设dp[x]表示把x变为1的期望,f[x]表示x的因子个数,根据全期望公式和期望的线性公式可得                    dp[x] = Σ(1/f[x])*(1 + dp[x / y])(y是x的因子且y不是1) + (1/f[x])*(1 + dp[x])                    =>  dp[x] = (f[x] + Σdp[x / y]) / (f[x] - 1)         利用dp记忆化搜索实现,具体实现技巧见注释*/#pragma warning(disable:4786)#pragma comment(linker, "/STACK:102400000,102400000")#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<stack>#include<queue>#include<map>#include<set>#include<vector>#include<cmath>#include<string>#include<sstream>#define LL long long#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)#define mem(a,x) memset(a,x,sizeof(a))#define lson l,m,x<<1#define rson m+1,r,x<<1|1using namespace std;const int INF = 0x3f3f3f3f;const int mod = 1e9 + 7;const double PI = acos(-1.0);const double eps=1e-6;const int maxn = 1e5 + 5;double dp[maxn];int f[maxn];void find_num(int n){    mem(f , 0);    for(int i = 1 ; i<= n ; i++)    f[i] = 1;    for(int i = 2 ; i <= n ; i++){        for(int j = i ; j<= n ; j += i){            f[j]++;        }    }}double dfs(int x){    if(x == 1)        return dp[1] = 0;    if(fabs(dp[x]) > eps)   return dp[x];    double sum = 0;    for(int i = 1 ; i * i<=x ; i++){    //如果直接从1到n枚举判断i是否是x因子会超时,故只枚举√n内的因子,那么i和x/i都是因子        if( x % i == 0 ){            if(i != 1)                sum += dfs(x / i);            if(i != x && i != x / i)                sum += dfs(i) ;        }    }    double p = f[x] + sum , q = f[x] - 1;    return dp[x] = p / q;}int main(){    //  freopen("D:\\professional debugging\\out10.txt","w",stdout);    mem(dp , 0);    find_num(1e5 + 2) ;    int T , n , kase = 0;    scanf("%d",&T);    while(T--){        scanf("%d",&n);        if(n == 1){            printf("Case %d: 0\n",++kase);            continue;        }        double ans = dfs(n);        printf("Case %d: %.12lf\n",++kase , ans);    }    return 0;}

0 0
原创粉丝点击