[ABC200F]Minflip Summation

Minflip Summation

题解

首先考虑不含 ? ? ?的情况。
由于它每次操作是对于一段区间异或 1 1 1,我们可以考虑先将整个序列差分,将异或的区间修改转化成单点修改。
由于修改成不同颜色的操作次数是等价的,我们不妨设就将整个序列改成与开头一样的取值,因此最后一个点的差分值就是它是否与开头一样。
很明显,对一段区间异或差分后就相当于对两个单点进行修改,与开头一样就是整个序列都是 0 0 0
所以我们的答案就是整个序列中 1 1 1的数量和的一半。
由于整个数列是重复 k k k次的,所以答案就是第一个差分序列的操作数的 k k k倍。

对于含 ? ? ?的,我们可以求出它的期望操作次数。
如果两个都是 ? ? ?,四种情况,两个不同,那么期望值就是 1 2 \frac{1}{2} 21
如果只有一个是 ? ? ?,有一半的概率与另一个不同,期望值也是 1 2 \frac{1}{2} 21
如果都不是,那么期望就是 0 / 1 0/1 0/1
注意总共整个序列是一个 ? ? ?的情况,这种情况也不需要改。

时间复杂度 O ( n ) O\left(n\right) O(n)

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#define lowbit(x) (x&-x)
#define reg register
#define mp make_pair
#define fir first
#define sec second
typedef long long LL;
typedef unsigned long long uLL;
const int INF=0x3f3f3f3f;
const LL mo=1e9+7;
const LL inv2=5e8+4;
const double Pi=acos(-1.0);
typedef pair<int,int> pii;
const double PI=acos(-1.0);
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
int n;char str[MAXN];LL ans,k;
LL add(LL x,LL y){return x+y<mo?x+y:x+y-mo;}
LL qkpow(LL a,LL s){LL t=1;while(s){if(s&1)t=1ll*a*t%mo;a=1ll*a*a%mo;s>>=1;}return t;}
signed main(){
	scanf("%s",str+1);n=(int)strlen(str+1);read(k);LL sum=0;if(1ll*n*k==1LL){puts("0");return 0;}
	for(int i=1;i<=n;i++)ans=add(ans,(str[i]=='?'||str[i%n+1]=='?')?inv2:(str[i]!=str[i%n+1])),sum+=(str[i]=='?');
	printf("%lld\n",1ll*k*ans%mo*inv2%mo*qkpow(qkpow(2LL,sum),k)%mo);
	return 0;
}


谢谢!!!

posted @ 2021-05-11 22:17  StaroForgin  阅读(12)  评论(0)    收藏  举报  来源