SHOI2017 分手是祝愿

分手是祝愿

有𝑛盏灯,给定每一盏灯的初始状态。每次操作可以选择一盏灯,将它的所有因数和它翻转。每次操作策略如下:

  1. 如果可以通过小于等于𝑘次操作把所有灯灭掉,那么直接按照最优策略进行。
  2. 否则,从1到𝑛中随机选择一盏灯进行操作。

求把所有灯灭掉的期望步数。

1 ≤ 𝑛 ≤ 105

题解

首先策略是唯一的。(为什么?每次考虑最大的元素,它只能通过操作自己灭掉)

所以我们可以得到一个01串,里面的每一个位置表示这个位置是否需要翻转。

然后所有的位置就等价了。

设𝑓𝑖表示有𝑖盏灯亮着的时候,灭掉其中一盏灯的期望步数。

在吴清月的PPT上第一次见到状态设成走一步的期望,最后求和的模式。

  1. 则当𝑖 > 𝑘时,
    \(f_i=\frac in+\frac{n-i}n(1+f_{i+1}+f_i)\) ,即\(f_i=\frac ni+\frac{n-i}i f_{i+1}\)
  2. 当𝑖 ≤ 𝑘时𝑓𝑖 = 1。

所以可以𝑂(𝑛)递推。

CO int N=100000+10;
int sta[N];
int dp[N];

int main(){
	int n=read<int>(),k=read<int>(); 
	for(int i=1;i<=n;++i) read(sta[i]);
	for(int i=n;i>=1;--i)if(sta[i]){
		for(int j=1;j*j<=i;++j)if(i%j==0){
			if(j!=i) sta[j]^=1;
			if(i/j!=j and i/j!=i) sta[i/j]^=1;
		}
	}
	int tot=0;
	for(int i=1;i<=n;++i) tot+=sta[i];
	for(int i=1;i<=k;++i) dp[i]=1;
	dp[n]=1;
	for(int i=n-1;i>k;--i){
		int inv=fpow(i,mod-2);
		dp[i]=add(mul(n,inv),mul(n-i,mul(inv,dp[i+1])));
	}
	int ans=0;
	for(int i=tot;i>=1;--i) ans=add(ans,dp[i]);
	for(int i=1;i<=n;++i) ans=mul(ans,i);
	printf("%d\n",ans);
	return 0;
}

posted on 2019-10-28 08:12  autoint  阅读(179)  评论(0编辑  收藏  举报

导航