【SDOI2017】数字表格

Description

【SDOI2017】数字表格_第1张图片

Solution

这道题明显可以用莫比乌斯反演来做,非常的裸的繁衍。
假设n < m
ans=ni=1mj=1f[gcd(i,j)]
那么直接枚举gcd=d
ans=nd=1f[d]g[d]
g[d]gcd=d
繁衍一下
g[d]=i|dndmdμ[di]
然后 ans=ni=1d|if[d]nimiμ[di]
s[i]=d|if[d]μ[di]
ans=ni=1s[i]nimi
然后去处理一下g的前缀积,分块做一下就好了。

Code

#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=1e6+7,mo=1e9+7;
ll i,j,k,l,t,n,m,ans,cas,r;
bool bz[maxn];
ll miu[maxn],p[maxn],sum[maxn],f[maxn],ji[maxn],g[maxn],chu[maxn][3];
ll qsm(ll x,ll y){
    if(y<0)y+=mo-1;
    ll z=1;
    for(;y;y/=2,x=x*x%mo)if(y&1)z=z*x%mo;
    return z;
}
int main(){
    freopen("product.in","r",stdin);
    freopen("product.out","w",stdout);
    miu[1]=sum[1]=f[1]=ji[1]=ji[0]=g[0]=g[1]=1;chu[1][0]=chu[1][1]=chu[1][2]=1;
    fo(i,2,maxn-7){
        f[i]=(f[i-1]+f[i-2])%mo;ji[i]=1;
        g[i]=1;
        if(!bz[i])p[++p[0]]=i,miu[i]=-1;
        fo(j,1,p[0]){
            t=p[j]*i;if(t>maxn-7)break;
            bz[t]=1;if(i%p[j]==0){break;}
            miu[t]=-miu[i];
        }
        sum[i]=sum[i-1]+miu[i];
        chu[i][0]=qsm(f[i],mo-2);chu[i][1]=1;chu[i][2]=f[i];
    }
    fo(i,1,maxn-7){
        fo(j,1,(maxn-7)/i){
            g[i*j]=g[i*j]*chu[i][miu[j]+1]%mo;
        }
        ji[i]=ji[i-1]*g[i]%mo;
    }
    for(scanf("%d",&cas);cas;cas--){
        scanf("%d%d",&n,&m);
        if(n>m)swap(n,m);ans=1;
        l=1;
        while(l<=n){
            r=min(n/(n/l),m/(m/l));
            t=0;
            t=(n/l)*(m/l)%(mo-1);
            ans=ans*qsm((ji[r]*qsm(ji[l-1],mo-2)%mo),t)%mo;
            l=r+1;
        }
        printf("%lld\n",ans);
    }
}

你可能感兴趣的:(数论,省选,莫比乌斯反演)