[ABC200F] Minflip Summation

前言

太妙啦!

本文只讲做法,不讲如何想到这个做法,没见过这个套路真的很难想啊。

题目

AtCoder

讲解

part1 01

我们先考虑没有问号的情况。

我们将所有数变为与第一个数相同的方法一定不劣。那么我们可以想到这样一个统计答案的方法,如果相邻两个数(按环考虑)不同,那么对答案的贡献为 \(\frac{1}{2}\)。用 \(C++\) 表示即:

\[\frac{\overset{|S|}{\underset{i=1}{\sum}}S_i==S_{i\%|S|+1} ? 0 : 1}{2} \]

反复 \(K\) 次只需要将答案乘 \(K\) 即可。

part2 ?

考虑扩展版本。

我们发现每个 \(?\) 成为 \(0\)\(1\) 的概率相同,而且彼此独立,所以我们可以求出期望再求出答案。

此时的答案为:

\[K\cdot \frac{\overset{|S|}{\underset{i=1}{\sum}}f(i,i\%|S|+1)}{2}\cdot 2^{cnt_?K} \]

其中的函数 \(f(x,y)\) 表示 \(S_x,S_y\) 对答案产生的贡献。

  • \(S_x\)\(S_y\) 其中一个是问号,那么显然对答案的贡献为 \(\frac{1}{2}\)
  • 否则相同贡献 \(0\),不同贡献 \(1\)

代码

int qpow(int x,int y)
{
	int ret = 1;
	while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
	return ret;
}
int Add(int x,int y)
{
	x += y; if(x >= MOD) x -= MOD;
	return x;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	scanf("%s",a+1);
	n = strlen(a+1); k = Read();
	for(int i = 1;i <= n;++ i)
	{
		int j = i+1 > n ? 1 : i+1; 
		if(a[i] == '?')	
		{
			cnt++;
			ans = Add(ans,inv2);
		}
		else if(a[j] == '?') ans = Add(ans,inv2);
		else if(a[i] != a[j]) ans = Add(ans,1);
	}
	ans = 1ll * ans * k % MOD * inv2 % MOD * qpow(2,1ll * cnt * k % (MOD-1)) % MOD;
	Put(ans);
	return 0;
}
posted @ 2021-05-13 14:41  皮皮刘  阅读(93)  评论(0)    收藏  举报