• uva 11762 数学期望+记忆化搜索


    题目大意:给一个正整数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=1000005;
    int prime[100000],Num;
    bool flag[Max],vis[Max];
    double f[Max];
    
    void Init()
    {
        int i,j;
        Num=0;
        for(i=2;i<Max;i++)
        {
            if(flag[i]) prime[Num++]=i;
            for(j=0;j<Num && i*prime[j]<Max;j++)
            {
                flag[i*prime[j]]=false;
                if(i%prime[j]==0) break;
            }
        }
    }
    
    double dp(int x)
    {
        if(x==1) return 0.0;
        if(vis[x]) return f[x];
        vis[x]=true;
        double sum=0;
        int p=0,g=0;
        for(int i=0;i<Num && prime[i]<=x;i++)
        {
            p++;
            if(x%prime[i]==0)
            {
                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=1;i<=t;i++)
        {
            scanf("%d",&n);
            printf("Case %d: %.10lf
    ",i,dp(n));
        }
        return 0;
    }
  • 相关阅读:
    【noi2018】归程
    【USACO06JAN】牛的舞会The Cow Prom
    City Horizon (线段树)
    USACO 2019 January Gold Cow Poetry (结论+dp)
    POJ 2528 Mayor's posters (线段树)
    线段覆盖 (线段树)
    POJ 2892 Tunnel Warfare (线段树)
    NOIP 2017 逛公园 (最短路+dp)
    USACO 2019 February Gold Cow Land (树链剖分)
    CSU 2151 集训难度(线段树)
  • 原文地址:https://www.cnblogs.com/xiong-/p/3259559.html
Copyright © 2020-2023  润新知