AtCoder Beginner Contest 200 F

这题的思路很清晰,和这题类似。

我们先考虑不将它重复\(k\)次,即字符串\(S\)所有的方案的和的平均数

首先,若没有?\(最少的次数=\lceil\frac{相邻两个数不同的个数}{2}\rceil\),那我们将每两个不同的字符的贡献看成\(\frac 1 2\),由于若相邻的不同的个数为奇数时要向上取整,我们发现,此时\(S_{|S|}\)\(S_{1}\)一定不是同一个数,比如下面的情况

11100011000

所以,我们把\(|S|\)\(1\)看成也是相邻的即可(类似环)。

?呢?

  • ?+0/1 或 0/1+?,可以计算贡献为\(\frac 1 4\)

  • ?+?

    • 0+01+1贡献为0;
    • 0+11+0贡献为1。

    即,总的贡献仍为\(\frac 1 4\)

这样,我们计算出所有\(S\)的答案的平均数\(num\),我们先将其乘\(k\)(重复\(k\)次),得到重复\(k\)次的平均数。而我们有\(2^{kq}\)种方案,\(q\)\(S\)中的?的数量。所以,答案为:

\[num\times k\times 2^{kq} \]

注意:

\(|S|=1\)\(k=1\)时,不存在相邻的字符,我们应特判,输出0

代码:

#include<bits/stdc++.h>
using namespace std;

#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define sz(v) (int)(v).size()
#define all(v) (v).begin(),(v).end()

typedef long long ll;
typedef pair<int,int> pi;

const ll mod=1000000007;
const ll inv2=500000004,inv4=250000002;
ll k,cnt,ans;
string s;

ll qpow(ll x,ll y) {
	if(y==0ll) return 1;
	ll ret=qpow(x,y>>1ll);
	ret*=ret,ret%=mod;
	if(y&1ll) ret*=x,ret%=mod;
	return ret;
}

ll calc(char x,char y) {
	if(x=='?'||y=='?') return inv4;
	if(x!=y) return inv2;
	return 0;
}

int main() {
	cin>>s>>k;
	if(sz(s)==1&&k==1) {
		puts("0");
		exit(0);
	}
	for(int i=0;i<sz(s);i++) {
		ans+=calc(s[i],s[(i+1)%sz(s)]);
		cnt+=(s[i]=='?');
		ans%=mod;
	}
	ans=ans*k%mod*qpow(2ll,cnt*k)%mod;
	cout<<ans<<endl;
	return 0;
}
posted @ 2022-07-09 20:00  Nastia  阅读(27)  评论(0)    收藏  举报