zoukankan      html  css  js  c++  java
  • [六省联考2017]分手是祝愿

    https://zybuluo.com/mdeditor#1094623

    标签(空格分隔): 期望


    题面

    B 君在玩一个游戏,这个游戏由 n 个灯和 n 个开关组成,给定这 n 个灯的初始状态,下标为从 1 到 n 的正整数。
    每个灯有两个状态亮和灭,我们用 1 来表示这个灯是亮的,用 0 表示这个灯是灭的,游戏的目标是使所有灯都灭掉。
    但是当操作第 i 个开关时,所有编号为 i 的约数(包括 1 和 i)的灯的状态都会被改变,即从亮变成灭,或者是从灭变成亮。
    B 君发现这个游戏很难,于是想到了这样的一个策略,每次等概率随机操作一个开关,直到所有灯都灭掉。
    这个策略需要的操作次数很多, B 君想到这样的一个优化。如果当前局面,可以通过操作小于等于 k 个开关使所有灯都灭掉,那么他将不再随机,直接选择操作次数最小的操作方法(这个策略显然小于等于 k 步)操作这些开关。
    B 君想知道按照这个策略(也就是先随机操作,最后小于等于 k 步,使用操作次数最小的操作方法)的操作次数的期望。
    这个期望可能很大,但是 B 君发现这个期望乘以 n 的阶乘一定是整数,所以他只需要知道这个整数对 100003 取模之后的结果。


    解析

    震惊,X省省选怒送80分,让无题不毒瘤的HNOI情何以堪。。。
    据说随便贪心从大到小枚举就有80分???哪还有谁会打正解呢???

    显然的期望公式(逆推,包括后继状态,(E_i)代表最快还要走(i)步时的期望)
    (E_i=frac{i}{n}E_{i-1}+frac{n-i}{n}E_{i+1}+1)
    没法递推啊。。。

    那么差分一下如何?((g_i)代表公差)
    (sum_{j=1}^ig_j=frac{i}{n}sum_{j=1}^{i-1}g_j+frac{n-i}{n}sum_{j=1}^{i+1}g_j+1)
    自己再化化简便得
    (g_i=frac{(n-i)g_{i+1}+n}{i})

    最后注意逆元不是素数,所以让我们回顾一下逆元线性递推公式。
    (inv[i]=(p-p/i)* inv[pmod i](p为取余数))

    // luogu-judger-enable-o2
    #include<iostream>
    #include<cmath>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #define ll long long
    #define re register
    #define il inline
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int mod=100003;
    int n,m,k,a[100005],dp[100005],inv[100005],b;
    vector<int>ysn[100005];
    ll ans,jc=1;
    il int gi()
    {
      re int x=0,t=1;
      re char ch=getchar();
      while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
      if(ch=='-') t=-1,ch=getchar();
      while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
      return x*t;
    }
    il ll ksm(re ll S,re ll n)
    {
      re ll T=S;S=1;
      while(n)
        {
          if(n&1) S=S*T%mod;
          T=T*T%mod;
          n>>=1;
        }
      return S;
    }
    int main()
    {
      n=gi();k=gi();
      fp(i,1,n) a[i]=gi(),(jc*=i)%=mod;
      fp(i,1,n)
        fp(j,1,sqrt(i))
        if(i%j==0)
          {//printf("%d %d
    ",i,j);
        ysn[i].push_back(j);
        if(j!=i/j) ysn[i].push_back(i/j);//printf("%d
    ",i/j);}
          }
      fq(i,n,1)
        {
          if(!a[i]) continue;
          for(re int j=0;j<ysn[i].size();j++)
        a[ysn[i][j]]=1-a[ysn[i][j]];
          ++b;
        }
      if(b<=k) return printf("%lld
    ",b*jc%mod),0;
          dp[n]=1;inv[1]=1;
          fp(i,2,n) inv[i]=(mod-1ll*(mod/i)*inv[mod%i]%mod)%mod;
          fq(i,n-1,k+1) dp[i]=(1ll*(n-i)*dp[i+1]%mod+n)%mod*inv[i]%mod;
          fp(i,1,b) ans+=((i>k)?dp[i]:1);
          printf("%lld
    ",ans*jc%mod);
      return 0;
    }
    
  • 相关阅读:
    【bzoj2733】永无乡(无旋treap启发式合并 + 并查集)
    【bzoj2002】弹飞绵羊(分块)
    【bzoj2724】蒲公英(分块)
    【最大M子段和】dp + 滚动数组
    【最大连续子段和】单调队列 + 前缀和优化
    【广告印刷】单调队列
    【烽火传递】dp + 单调队列优化
    【志愿者选拔】单调队列、输入优化
    【Sliding Window】单调队列
    【序列操作V】平衡树(无旋treap)
  • 原文地址:https://www.cnblogs.com/yanshannan/p/8679541.html
Copyright © 2011-2022 走看看