[2017集训队作业自选题#115]Replace All

49 篇文章 1 订阅
27 篇文章 0 订阅

题解

推荐wxh
可爱的修修
本题相较于CF794G,n加0了。
我们需要快速计算
ni=1nj=12(i,j)
nd=12dn/di=1n/dj=1[(i,j)=1]
nd=12d(2n/di=1ϕ(i)1)
分块杜教筛即可。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=300000+10,maxd=5000000+10,maxha=maxd*5,mo=1000000007,inv2=(mo+1)/2;
char a[maxn],b[maxn];
int fac[maxn*2],inv[maxn*2];
int pri[maxd],phi[maxd],gg[maxd],ha[maxha+100][2];
bool bz[maxd];
int i,j,k,l,r,t,m,lena,lenb,d,da,db,dda,ddb,p,q,c,cnt,ans,top;
ll n,N,nn;
bool czy;
int qsm(int x,ll y){
    if (!y) return 1;
    int t=qsm(x,y/2);
    t=(ll)t*t%mo;
    if (y%2) t=(ll)t*x%mo;
    return t;
}
int S(int n){
    return (ll)n*(n+1)%mo*inv2%mo;
}
int getha(ll n){
    int k=(n-1)%maxha+1;
    while (ha[k][0]!=n&&ha[k][0]!=0) k=(k==maxha)?1:k+1;
    return k;
}
int getphi(ll n){
    if (n<=maxd-10) return phi[n];
    int k=N/n;
    if (gg[k]) return gg[k];
    ll i=2,j;
    int t=S(n%mo),l;
    while (i<=n){
        j=n/(n/i);
        l=getphi(n/i);
        (t-=(ll)((j-i+1)%mo)*l%mo)%=mo;
        i=j+1;
    }
    return gg[k]=t;
}
void prepare(){
    fac[0]=1;
    fo(i,1,m) fac[i]=(ll)fac[i-1]*i%mo;
    inv[m]=qsm(fac[m],mo-2);
    fd(i,m-1,0) inv[i]=(ll)inv[i+1]*(i+1)%mo;
    phi[1]=1;
    fo(i,2,maxd-10){
        if (!bz[i]){
            phi[i]=i-1;
            pri[++top]=i;
        }
        fo(j,1,top){
            if ((ll)i*pri[j]>maxd-10) break;
            bz[i*pri[j]]=1;
            if (i%pri[j]==0){
                phi[i*pri[j]]=phi[i]*pri[j];
                break;
            }
            phi[i*pri[j]]=phi[i]*(pri[j]-1);
        }
    }
    fo(i,1,maxd-10) (phi[i]+=phi[i-1])%=mo;
    /*fo(i,1,n){
        t=qsm(2,i);
        l=(2*phi[n/i]-1)%mo;
        (c+=(ll)t*l%mo)%=mo;
    }*/
    l=1;
    ll i=1,j;
    while (i<=n){
        j=n/(n/i);
        r=(qsm(2,j+1)-1)%mo;
        (c+=(ll)(r-l)*((2*getphi(n/i)-1)%mo)%mo)%=mo;
        l=r;
        i=j+1;
    }
}
int C(int n,int m){
    if (n<m||m<0) return 0;
    return (ll)fac[n]*inv[m]%mo*inv[n-m]%mo;
}
int gcd(int a,int b){
    return b?gcd(b,a%b):a;
}
int main(){
    //freopen("data.in","r",stdin);
    scanf("%s",a+1);
    lena=strlen(a+1);
    scanf("%s",b+1);
    lenb=strlen(b+1);
    m=lena+lenb;
    scanf("%lld",&n);
    N=n;
    prepare();
    fo(i,1,lena)
        if (a[i]=='A') da++;
        else if (a[i]=='B') db++;
        else p++;
    fo(i,1,lenb)
        if (b[i]=='A') da--;
        else if (b[i]=='B') db--;
        else q++;
    fo(d,-q,p){
        t=C(p+q,q+d);
        dda=da+d;ddb=db+p-q-d;
        if (dda==0&&ddb==0){
            (ans+=(ll)t*c%mo)%=mo;
            continue;
        }
        if ((ll)dda*ddb<0){
            dda=abs(dda);ddb=abs(ddb);
            nn=(ll)n/(max(dda,ddb)/gcd(dda,ddb))+1;
            nn=(qsm(2,nn)-2)%mo;
            (ans+=(ll)t*nn%mo)%=mo;
        }
    }
    if (lena==lenb){
        czy=1;
        cnt=0;
        fo(i,1,lena)
            if (a[i]=='?'&&b[i]=='?') cnt++;
            else if (a[i]!='?'&&b[i]!='?'&&a[i]!=b[i]){
                czy=0;
                break;
            }
        if (czy){
            (ans-=(ll)qsm(2,cnt)*c%mo)%=mo;
            c=(qsm(2,n+1)-2)%mo;
            c=(ll)c*c%mo;
            (ans+=(ll)qsm(2,cnt)*c%mo)%=mo;
        }
    }
    (ans+=mo)%=mo;
    printf("%d\n",ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值