codeforces 794G. Replace All

来源:互联网 发布:ubuntu 传输文件 编辑:程序博客网 时间:2024/05/19 16:03

题目大意:给两个'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 longusing 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^dfor (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-vint 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);}


原创粉丝点击