[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;
}

浙公网安备 33010602011771号