zoukankan      html  css  js  c++  java
  • 【BZOJ】4872: [Shoi2017]分手是祝愿 期望DP

    【题意】给定n盏灯的01状态,操作第 i 盏灯会将所有编号为 i 的约数的灯取反。每次随机操作一盏灯直至当前状态能够在k步内全灭为止(然后直接灭),求期望步数。n,k<=10^5。

    【算法】期望DP

    【题解】对于当前状态,编号最大的亮灯必须通过操作自身灭掉

    证明:假设通过操作编号更大的灯灭掉,那么编号更大的灯只能通过操作自己灭掉,则与原来状态无区别,得证。

    运用这个结论,每次灭掉最大编号的灯后的局面中,编号最大的灯一定严格小于原最大灯,所以至多需要n次操作。

    从大到小,处理出m盏待操作灯,这样一个局面就可以描述成待操作灯的数目,从而考虑期望DP。

    最直观地,设f[i]表示剩余 i 盏操作灯的期望步数,根据全期望公式:

    $$f[i]=frac{i}{n}*f[i-1]+frac{n-i}{n}*f[i+1]+1$$

    等等,高斯消元?不资瓷!我们想办法变成单方向DP,去掉f[i-1]。

    设f[i]表示从 i 盏待操作灯变成 i-1 盏待操作灯的期望步数,那么根据全期望公式:(省略i/n*0)

    $$f[i]=frac{n-i}{n}*(f[i+1]+f[i])+1$$

    好啦!移项即可计算f[i],最后:

    $$ans=sum_{i=k+1}^{m}f[i]*n!$$

    复杂度O(n√n)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=100010,MOD=100003;
    int n,m,k,ans,a[maxn],f[maxn];
    void exgcd(int a,int b,int &x,int &y){if(!b){x=1;y=0;}else{exgcd(b,a%b,y,x);y-=x*(a/b);}}
    int inv(int a){int x,y;exgcd(a,MOD,x,y);return (x%MOD+MOD)%MOD;}
    int main(){
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);
        for(int i=n;i>=1;i--)if(a[i]){
            m++;
            for(int j=1;j*j<=i;j++)if(i%j==0){
                if(j*j==i)a[j]^=1;else a[j]^=1,a[i/j]^=1;
            }
        }
        for(int i=n;i>k;i--)f[i]=(n+1ll*(n-i)*f[i+1]%MOD)*inv(i)%MOD;
        if(m<=k)ans=m;else{
            for(int i=m;i>k;i--)ans=(ans+f[i])%MOD;
            ans=(ans+k)%MOD;
        }
        for(int i=1;i<=n;i++)ans=1ll*ans*i%MOD;
        printf("%d",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    七十年前往事的回顾:偷窥造酒作坊的裸体男人
    Python画图工具matplotlib的安装
    版本号控制-搭建gitserver
    HDU 4405 概率期望DP
    下载jdk文件后缀是.gz而不是.tar.gz怎么办
    《小亚和小信》小强,你就长点心吧!
    7.11 小结
    动态规划 LCS,LIS
    每秒更新时间 v-text的应用 (解决闪现{}问题)
    vue 引入组件
  • 原文地址:https://www.cnblogs.com/onioncyc/p/8521851.html
Copyright © 2011-2022 走看看