zoukankan      html  css  js  c++  java
  • bzoj 4872: [Shoi2017]分手是祝愿 期望dp

    题意:给定 $n$ 个灯的初始开/关状态,每次可以随机选择一个点进行操作,当操作第 $i$ 个开关时,所有 $i$ 的约数的灯的状态都会改变. 当操作到局面最少小于等于 $k$ 步就能将所有灯灭掉时就不用随机,而直接选取最优方案.

    求:让所有灯全部灭掉的期望操作次数.

    加入给定一个局面,那么最优解一定是从编号大的灯向编号小的灯开始操作(因为小灯管不了大灯)

    这样,你在省选的时候能拿到 $50pts$ 的暴力分~

    然而,分析到这一步就毫无思路了~

    但是呢,我们发现这道题中最小操作次数非常关键:如果最小操作次数小于等于 $k$ 就可以直接操作而不再随机了.

    即我们可以只考虑当前局面最优操作次数,从而在最优操作次数上做文章.

    有一个性质:如果操作编号是固定的,那么先后顺序是无所谓的.

    假设当前最优操作次数为 $a$,即 $n$ 个编号中有 $a$ 个会使局面更优的操作点,那么其余点都会使局面更差.

    想到这里,我们令 $f[i]$ 表示从最优操作次数为 $i$ 的局面到最优操作次数为 $(i-1)$ 的操作次数.

    则有 $f[i]=(f[i]+f[i+1]) imes frac{n-i}{n}+1 imes frac{i}{n}$,整理得:$f[i]=f[i+1] imes frac{n-i}{i}+1$

    最后在计算答案是只需从初始局面所对应得最优移动步数开始累计即可. 

    #include <bits/stdc++.h>    
    #define N 100005           
    #define mod 100003   
    #define LL long long     
    #define setIO(s) freopen(s".in","r",stdin)        
    using namespace std;
    LL fac[N],inv[N],dp[N];    
    int sta[N],v[N]; 
    LL qpow(LL x,LL y) 
    {
        LL tmp=1ll; 
        for(;y;y>>=1,x=x*x%mod)  if(y&1)    tmp=tmp*x%mod;    
        return tmp;    
    }   
    LL Inv(LL x) { return qpow(x,mod-2);   }
    int main() 
    {
        // setIO("input");           
        int i,j,n,k,stp=0; 
        scanf("%d%d",&n,&k);
        fac[0]=inv[0]=1ll;       
        for(i=1;i<=n;++i)    fac[i]=fac[i-1]*1ll*i%mod,inv[i]=Inv(fac[i]);      
        for(i=1;i<=n;++i)    scanf("%d",&sta[i]);              
        for(i=n;i>=1;--i) 
        { 
            sta[i]^=v[i];   
            if(sta[i]) 
            {
                ++stp;                           
                for(j=1;j*j<=i;++j)  if(i%j==0) 
                { 
                    v[j]^=1;          
                    if(j!=i/j)  v[i/j]^=1;               
                }
            }
        }                            
        // printf("%d
    ",stp);              
        // dp[n]=1;   
        for(i=n;i>=1;--i) dp[i]=(dp[i+1]*1ll*(n-i)%mod+n)%mod*qpow(i,mod-2)%mod;          
        LL ans=0ll;  
        if(stp<=k)  ans=stp;      
        else 
        {    
            for(i=stp;i>k;--i) ans=(ans+dp[i])%mod;                                   
            ans=(ans+k)%mod;   
        }  
        for(i=1;i<=n;++i)    ans=ans*1ll*i%mod;   
        printf("%lld
    ",ans);    
        return 0;    
    }
    

      

  • 相关阅读:
    微软推出的免费新书《Introducing Microsoft SQL Server 2012》
    关于Installshield中Ie8\Ie9\SQL Server 2008 R2 Native Client等Prq文件在线下载地址
    PowerDesigner批量生成日期型、中文字符型、数字型测试数据
    在服务器上使用第三方独立组件对Word/Excel进行编程
    文明源自谎言
    中文写程序,何陋之有?
    在线网摘收藏?让Google来吧!
    下载文件时根据MIME类型自动判断保存文件的扩展名
    谨慎注意WebBrowser控件的DocumentCompleted事件
    你的命运谁攥着?
  • 原文地址:https://www.cnblogs.com/guangheli/p/11773220.html
Copyright © 2011-2022 走看看