题目大意:给两个'A''B''?'组成的串XY,'?'可以是'A'或'B',求所有'?'的情况下,将'A''B'换成两个长度小于n的01串的方案数和。
这好像有一些奥妙重重的性质。
先考虑一个简单的情况:第一个串有a个'A',第二个串有b个'B'。设'A'=>A,'B'=>B。b*|A|=a*|B|,且AB串coprime(是官方题解中的说法,互质,就像辗转相除法一样的感觉)。由于这样的性质,不妨设B=AX,X是一个串。存在AB=BA。
如果AB互质,"AB"="BA",对任何询问都能转换"A..AB..B","A..AB..B"。如果这两个串不同,等价于上面情况,可以直接做,否则即要统计互质的AB串对数,使用容斥解决。
但是如果AB不互质,刚才的方法还是无法解决(此处强调AB是求出来的答案01串)。经过分析,X!=Y时,AB互质,证明略;X==Y时,A==B,容易计算。
至此问题已解决,复杂度O(nlogn+len)。
#include<bits/stdc++.h>
#define P 1000000007
#define N 600005
#define ll long long
using namespace std;
int l1,l2,n,Aa,Ba,Ca,Ab,Bb,Cb,flag,CC;
ll ans,inv[N],sum[N],po[N],fac[N],ifac[N],G;
char a[N],b[N];
int gcd(int x,int y)
{
return y?gcd(y,x%y):x;
}
ll C(int x,int y)
{
return fac[y]*ifac[y-x]%P*ifac[x]%P;
}
int main()
{
scanf("%s%s",a+1,b+1);
l1=strlen(a+1);
l2=strlen(b+1);
scanf("%d",&n);
/**/
po[0]=1;
for (int i=1;i<=600000;i++)
po[i]=po[i-1]*2%P;
inv[1]=1;
for (int i=2;i<=600000;i++)
inv[i]=(-P/i)*inv[P%i]%P;
fac[0]=1;ifac[0]=1;
for (int i=1;i<=600000;i++)
fac[i]=fac[i-1]*i%P,ifac[i]=ifac[i-1]*inv[i]%P;
flag=l1==l2;
for (int i=1;i<=l1;i++)
{
if (a[i]=='A') Aa++;
if (a[i]=='B') Ba++;
if (a[i]=='?') Ca++;
flag&=a[i]==b[i]||a[i]=='?'||b[i]=='?';
if (a[i]=='?'&&b[i]=='?') CC++;
}
for (int i=1;i<=l2;i++)
{
if (b[i]=='A') Ab++;
if (b[i]=='B') Bb++;
if (b[i]=='?') Cb++;
}
//calc G 小于n的coprime串对数 gcd (n/d)^2*2^d
for (int i=1;i<=n;i++)
sum[i]=(ll)(n/i)*(n/i)%P;
for (int i=n;i>=1;i--)
{
for (int j=2;j<=n/i;j++)
sum[i]=(sum[i]-sum[i*j])%P;
G=(G+sum[i]*po[i]%P)%P;
}
for (int i=-Cb;i<=Ca;i++)
{
//a: Aa+u Ba+Ca-u
//b: Ab+v Bb+Cb-v
//magic
//a: Aa-Ab+u-v
//b: Bb+Cb-Ba-Ca-v+u
//i=u-v
int A=Aa-Ab+i,B=Bb+Cb-Ba-Ca+i;ll t=C(Cb+i,Ca+Cb);
if ((ll)A*B<0) continue;
if (A<=0&&B<=0) A=-A,B=-B;
if (A==0&&B==0)
{
//cout<<G<<endl;
if (flag)
{
ans=(ans+(po[n+1]-2)*(po[n+1]-2)%P*po[CC]%P)%P;
t=(t-po[CC]+P)%P;
}
ans=(ans+t*G)%P;
continue;
}
if (A>B) swap(A,B);
if (A==0) continue;
ans=(ans+t*(po[n/(B/gcd(A,B))+1]-2)%P)%P;
//cout<<A<<' '<<B<<' '<<t<<' '<<ans<<endl;
}
printf("%lld\n",(ans+P)%P);
}