[关闭]
@ysner 2018-03-30T16:20:57.000000Z 字数 1946 阅读 1673

[六省联考2017]分手是祝愿

期望


题面

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分???哪还有谁会打正解呢???

显然的期望公式(逆推,包括后继状态,代表最快还要走步时的期望)

没法递推啊。。。

那么差分一下如何?(代表公差)

自己再化化简便得

最后注意逆元不是素数,所以让我们回顾一下逆元线性递推公式。

  1. // luogu-judger-enable-o2
  2. #include<iostream>
  3. #include<cmath>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<cstdlib>
  7. #include<algorithm>
  8. #include<vector>
  9. #define ll long long
  10. #define re register
  11. #define il inline
  12. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  13. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  14. using namespace std;
  15. const int mod=100003;
  16. int n,m,k,a[100005],dp[100005],inv[100005],b;
  17. vector<int>ysn[100005];
  18. ll ans,jc=1;
  19. il int gi()
  20. {
  21. re int x=0,t=1;
  22. re char ch=getchar();
  23. while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  24. if(ch=='-') t=-1,ch=getchar();
  25. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  26. return x*t;
  27. }
  28. il ll ksm(re ll S,re ll n)
  29. {
  30. re ll T=S;S=1;
  31. while(n)
  32. {
  33. if(n&1) S=S*T%mod;
  34. T=T*T%mod;
  35. n>>=1;
  36. }
  37. return S;
  38. }
  39. int main()
  40. {
  41. n=gi();k=gi();
  42. fp(i,1,n) a[i]=gi(),(jc*=i)%=mod;
  43. fp(i,1,n)
  44. fp(j,1,sqrt(i))
  45. if(i%j==0)
  46. {//printf("%d %d\n",i,j);
  47. ysn[i].push_back(j);
  48. if(j!=i/j) ysn[i].push_back(i/j);//printf("%d\n",i/j);}
  49. }
  50. fq(i,n,1)
  51. {
  52. if(!a[i]) continue;
  53. for(re int j=0;j<ysn[i].size();j++)
  54. a[ysn[i][j]]=1-a[ysn[i][j]];
  55. ++b;
  56. }
  57. if(b<=k) return printf("%lld\n",b*jc%mod),0;
  58. dp[n]=1;inv[1]=1;
  59. fp(i,2,n) inv[i]=(mod-1ll*(mod/i)*inv[mod%i]%mod)%mod;
  60. fq(i,n-1,k+1) dp[i]=(1ll*(n-i)*dp[i+1]%mod+n)%mod*inv[i]%mod;
  61. fp(i,1,b) ans+=((i>k)?dp[i]:1);
  62. printf("%lld\n",ans*jc%mod);
  63. return 0;
  64. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注