[数论 反演]BZOJ4816 [Sdoi2017]数字表格

来源:互联网 发布:mysql数据库教学视频 编辑:程序博客网 时间:2024/05/14 07:01

推一推
答案是

T(d|Tfμ(Td)d)nTmT

O(nlnn)筛一下括号里的东西,分块搞

include <cstdio>#include <iostream>#include <algorithm>using namespace std;typedef long long ll;const int N=1000010,P=1e9+7;int t,n,m,mu[N],p[N],g[N],f[N],h[N],invh[N];inline int Pow(int x,ll y){    int ret=1;    for(;y;y>>=1,x=1LL*x*x%P) if(y&1) ret=1LL*ret*x%P;    return ret;}inline void Pre(const int x){    mu[1]=1;    for(int i=2;i<=x;i++){        if(!p[i]) p[++*p]=i,mu[i]=-1;        for(int j=1;j<=*p && 1LL*p[j]*i<=x;j++)            if(p[p[j]*i]=1,i%p[j]) mu[i*p[j]]=-mu[i];            else{                mu[i*p[j]]=0; break;            }    }    for(int i=1;i<=x;i++) g[i]=1;    f[1]=f[2]=1;    for(int i=3;i<=x;i++) f[i]=(f[i-1]+f[i-2])%P;    for(int i=2;i<=x;i++){        int INV=Pow(f[i],P-2);        for(int j=i;j<=x;j+=i){            if(mu[j/i]==0) continue;            if(mu[j/i]==-1) g[j]=1LL*g[j]*INV%P;            else g[j]=1LL*g[j]*f[i]%P;        }    }    h[0]=invh[0]=1;    for(int i=1;i<=x;i++) h[i]=1LL*h[i-1]*g[i]%P,invh[i]=Pow(h[i],P-2);}int ans;int main(){    scanf("%d",&t); Pre(N-10);    while(t--){        scanf("%d%d",&n,&m);        if(n>m) swap(n,m);        ans=1;        for(int i=1,nxt;i<=n;i=nxt+1){            nxt=min(n/(n/i),m/(m/i));            ans=1LL*ans*Pow(1LL*h[nxt]*invh[i-1]%P,1LL*(n/i)*(m/i))%P;        }        printf("%d\n",ans);    }    return 0;}
原创粉丝点击