*3400的难度,比较恶心的推式子题。
第一个结论,对于给定的串 s , t s,t s,t,若 ∣ s ∣ ≠ ∣ t ∣ |s|\ne |t| ∣s∣=∣t∣,并且其拼接完全相同(至少有一个位置不一样),那么一定可以把 s , t s,t s,t拆分成长度为 gcd ( ∣ s ∣ , ∣ t ∣ ) \gcd(|s|,|t|) gcd(∣s∣,∣t∣)的串的拼接。于是我们不关心这个串具体长什么样,只要最后拆分出来的数目一样就好了。因此方案数为 2 gcd ( ∣ s ∣ , ∣ t ∣ ) 2^{\gcd(|s|,|t|)} 2gcd(∣s∣,∣t∣)。(这个地方刚开始推错了,后面又改对了,不过没过大样例的原因好像是有些情况没有特判到。)这个结论还是非常好猜的。
换一个角度理解,其实也可以看成 p 1 = s gcd ( ∣ s ∣ , ∣ t ∣ ) , p 2 = t gcd ( ∣ s ∣ , ∣ t ∣ ) p_1=\frac{s}{\gcd(|s|,|t|)},p_2=\frac{t}{\gcd(|s|,|t|)} p1=gcd(∣s∣,∣t∣)s,p2=gcd(∣s∣,∣t∣)t,其中 gcd ( p 1 , p 2 ) = 1 \gcd(p_1,p_2)=1 gcd(p1,p2)=1,这样同样是不重不漏的。
然后我们着手处理第二个部分。假设第一个串拆分出了 A + i A+i A+i个 p 1 p_1 p1, B − i B-i B−i个 p 2 p_2 p2,第二个串拆分出了 C + j C+j C+j个 p 1 p_1 p1, D − j D-j D−j个 p 2 p_2 p2。其中 i ∈ [ 0 , C 1 ] , j ∈ [ 0 , C 2 ] i\in [0,C_1],j\in [0,C_2] i∈[0,C1],j∈[0,C2]。
不难得出等式: p 1 ( A + i ) + p 2 ( B − i ) = p 1 ( C + j ) + p 2 ( D − j ) p_1(A+i)+p_2(B-i)=p_1(C+j)+p_2(D-j) p1(A+i)+p2(B−i)=p1(C+j)+p2(D−j)
解得 i − j = p 1 C + p 2 D − p 1 A − p 2 B p 1 − p 2 i-j=\frac{p_1C+p_2D-p_1A-p_2B}{p_1-p_2} i−j=p1−p2p1C+p2D−p1A−p2B为定值。这是个令人兴奋的结果,因为我们记这个定值为 s s s,那么这部分方案数是 ∑ ( C 1 i ) ( C 2 i − s ) = ∑ ( C 1 i ) ( C 2 C 2 + s − i ) = ( C 1 + C 2 C 2 + s ) \sum \binom{C_1}{i}\binom{C_2}{i-s}=\sum \binom{C_1}{i}\binom{C_2}{C_2+s-i}=\binom{C_1+C_2}{C_2+s} ∑(iC1)(i−sC2)=∑(iC1)(C2+s−iC2)=(C2+sC1+C2)。
用上面式子直接算,复杂度 O ( n 2 ) O(n^2) O(n2)。
下一步非常运气。我们可以把式子写成: p 1 ( s + M ) = p 2 ( s + N ) p_1(s+M)=p_2(s+N) p1(s+M)=p2(s+N)。首先让 s + M , s + N s+M,s+N s+M,s+N互质,又因为 p 1 , p 2 p_1,p_2 p1,p2互质,所以 p 1 = s + N , p 2 = s + M p_1=s+N,p_2=s+M p1=s+N,p2=s+M,然后就做完了???
复杂度 O ( n ) O(n) O(n)。
最后还是讲一下最难的部分,也就是算重的问题。如果处理的不好就会很麻烦。
首先我们计算 s + M ≠ 0 s+M\ne 0 s+M=0且 s + N ≠ 0 s+N\ne 0 s+N=0的情形。应当注意到,此时 A A A或者 B B B的数目不相等,如果 ∣ s ∣ ≠ ∣ t ∣ |s|\ne |t| ∣s∣=∣t∣那么必然出现交叉,也就是说 s , t s,t s,t一定能拆成 gcd ( ∣ s ∣ , ∣ t ∣ ) \gcd(|s|,|t|) gcd(∣s∣,∣t∣),按上式算即可。如果 ∣ s ∣ = ∣ t ∣ |s|=|t| ∣s∣=∣t∣,那么意味着 s = t s=t s=t,只要判断 ∣ a ∣ = ∣ b ∣ |a|=|b| ∣a∣=∣b∣即可。
然后我们计算 s + M = 0 , s + N = 0 s+M=0,s+N=0 s+M=0,s+N=0的情形。同理,如果 ∣ s ∣ ≠ ∣ t ∣ |s|\ne |t| ∣s∣=∣t∣,并且 a ≠ b a\ne b a=b,那么还是按上式算,显然此时 p 1 , p 2 p_1,p_2 p1,p2可以取任意值,不过因为 s s s是定值,所以可以把组合数提出来,相当于是算 ( ( C 1 + C 2 C 2 + s ) − 2 t o t ) ∑ i ≠ j 2 gcd ( i , j ) (\binom{C_1+C_2}{C_2+s}-2^{tot})\sum_{i\ne j}2^{\gcd(i,j)} ((C2+sC1+C2)−2tot)∑i=j2gcd(i,j),这个可以用数论函数预处理就不说了。最后如果 ∣ s ∣ = ∣ t ∣ |s|=|t| ∣s∣=∣t∣,并且 a ≠ b a\ne b a=b,那么意味着 s = t s=t s=t,相当于是 ( ( C 1 + C 2 C 2 + s ) − 2 t o t ) ∑ i ≤ n 2 i (\binom{C_1+C_2}{C_2+s}-2^{tot})\sum_{i\le n}2^i ((C2+sC1+C2)−2tot)∑i≤n2i。注意这一大类还应该考虑 a = b a=b a=b的情形,也就是 2 t o t ( ∑ i ≤ n 2 i ) 2 2^{tot}(\sum_{i\le n}2^i)^2 2tot(∑i≤n2i)2。
不得不承认最后这一步容斥还是很高妙的。考场上能把这个部分想清楚也确实不容易
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
const int N=2e6+5;
string a,b;
int n;
ll f[N],sum[N],res,fac[N],inv[N],A,B,C,D,C1,C2;
ll phi[N];
int prime[N/10],cnt;
bool vis[N];
ll fpow(ll x,ll y=mod-2){
ll z(1);
for(;y;y>>=1){
if(y&1)z=z*x%mod;
x=x*x%mod;
}
return z;
}
void init(int n){
f[0]=fac[0]=1;for(int i=1;i<=n;i++)f[i]=f[i-1]*2%mod,sum[i]=(f[i]+sum[i-1])%mod,fac[i]=fac[i-1]*i%mod;
inv[n]=fpow(fac[n]);for(int i=n;i>=1;i--)inv[i-1]=inv[i]*i%mod;
phi[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[++cnt]=i,phi[i]=i-1;
}
for(int j=1;j<=cnt&&prime[j]<=n/i;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
for(int i=2;i<=n;i++){
phi[i]=(phi[i-1]+phi[i])%mod;
}
}
ll binom(int x,int y){
if(x<y||y<0)return 0;
assert(x>=y),assert(y>=0);
return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
void add(ll &x,ll y){
x=(x+y)%mod;
}
int gcd(int x,int y){
return y==0?x:gcd(y,x%y);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>a>>b>>n;
for(int i=0;i<a.size();i++){
if(a[i]=='?')C1++,B++;
else if(a[i]=='A')A++;
else B++;
}
for(int i=0;i<b.size();i++){
if(b[i]=='?')C2++,D++;
else if(b[i]=='A')C++;
else D++;
}
init(max((int)a.size()+(int)b.size(),2*n));
for(ll s=-C2;s<=C1;s++){
ll x=A-C+s,y=D-B+s;
if(x==0&&y==0){
assert(a.size()==b.size());
int ok=1,tot=0;
for(int i=0;i<a.size();i++){
if(a[i]!='?'&&b[i]!='?'&&a[i]!=b[i])ok=0;
if(a[i]=='?'&&b[i]=='?')tot++;
}
if(ok){
for(int i=1;i<=n;i++){
add(res,f[i]*(phi[n/i]-1)%mod*(binom(C1+C2,C2+s)-f[tot])%mod*2);
}
add(res,(binom(C1+C2,C2+s)-f[tot])*sum[n]);
add(res,f[tot]*sum[n]%mod*sum[n]);
}
else{
for(int i=1;i<=n;i++){
add(res,f[i]*(phi[n/i]-1)%mod*binom(C1+C2,C2+s)%mod*2);
}
add(res,binom(C1+C2,C2+s)*sum[n]);
}
}
else if(x!=0&&y!=0){
if(a.size()==b.size()){
add(res,binom(C1+C2,C2+s)*sum[n]);
}
if(!((x>0)^(y>0))&&x!=y){
x=abs(x),y=abs(y);
ll z=gcd(x,y);
x/=z,y/=z;
assert(gcd(x,y)==1);
add(res,binom(C1+C2,C2+s)*sum[min(n/y,n/x)]);
}
}
}
cout<<(res+mod)%mod;
}