[ABC200E] Minflip Summation

一、题目

题目描述

一个字符串 \(T\) 是由一个包含 \(0,1,?\) 的字符串 \(S\) 循环连接 \(k\) 次获得的。

字符串 \(T\) 中的每个 \(?\) 都可以换成 \(0\)\(1\),设得到的串是 \(T'\),求:

\[\sum F(T') \]

其中 \(F(T')\) 定义为把字符串通过区间异或 \(1\) 的方式变成相同的最小操作数。

\(1\leq |S|\leq 10^5,1\leq k\leq 10^9\)

解法

别被题目吓到了,其实是个水题。

首先想一想怎么才能做一个没有问号的序列 \(S\),可以把 \(S\) 差分,即得到数组 \(s_1\oplus s_2....s_{n}\oplus s_1\),不难发现这样做一定会有偶数个 \(1\),而且每次通过区间操作可以消掉一对 \(1\),并且 \(S\) 复制 \(k\) 次的差分数组就是 \(S\) 的差分数组复制 \(k\) 次获得的,不难写出答案:

\[k\times \frac{\sum_{i=1}^n[s_i=s_{i\%n+1}]}{2} \]

然后再把问号考虑进来,可以先求出期望再乘以总方案数,只考虑 \([s_i=s_{i\%n+1}]\) 的期望是好算的:

  • 如果 \(s_i=?\or s_{i\% n+1}=?\),不难发现期望是 \(50\%\)
  • 否则期望是 \([s_i=s_{i\%n+1}]\)

但是注意 \(n=k=1\) 并且字符是 \(?\) 的时候会出问题(期望算错了),需要特判。

#include <cstdio>
#include <cstring>
const int M = 100005;
const int MOD = 1e9+7;
const int i2 = (MOD+1)/2;
#define int long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,k,ans,t=1;char s[M];
int qkpow(int a,int b)
{
	int r=1;
	while(b>0)
	{
		if(b&1) r=r*a%MOD;
		a=a*a%MOD;
		b>>=1;
	}
	return r;
}
signed main()
{
	scanf("%s",s+1);k=read();
	n=strlen(s+1);
	if(n*k==1) {puts("0");return 0;}
	for(int i=1;i<=n;i++)
	{
		int j=i%n+1;
		if(s[i]=='?') t=t*2%MOD;
		if(s[i]=='?' || s[j]=='?') ans=(ans+i2)%MOD;
		else if(s[i]!=s[j]) ans++;
	}
	ans=ans*k%MOD*i2%MOD*qkpow(t,k)%MOD;
	printf("%lld\n",ans);
}
posted @ 2021-05-12 20:35  C202044zxy  阅读(86)  评论(0编辑  收藏  举报