BZOJ4816 [Sdoi2017]数字表格

来源:互联网 发布:星野竜一 知乎 编辑:程序博客网 时间:2024/05/21 11:08

我们要求i=1nj=1mf[gcd(i,j)]

构造函数g,使得i|ng[i]=f[i]
那么要求的就变成了i=1nj=1md|iandd|jg[d]
更换枚举顺序把d提前,得到d=1ng[d]ndmd
分块即可
至于如何求g,由我们构造g的方法可得g[x]=f[x]i|xandi!=xg[i]
那么对于每个i,求出g[i]后枚举i的所有倍数然后除以g[i]即可,由调和级数得预处理部分的复杂度是n log的

#include<iostream>#include<cstring>#include<ctime>#include<cmath>#include<algorithm>#include<iomanip>#include<cstdlib>#include<cstdio>#include<map>#include<bitset>#include<set>#include<stack>#include<vector>#include<queue>using namespace std;#define MAXN 1000010#define MAXM 1010#define ll long long#define eps 1e-8#define MOD 1000000007#define INF 1000000000ll f[MAXN],g[MAXN],ng[MAXN];int n,m;ll mi(ll x,ll y){    ll re=1;    while(y){        if(y&1){            (re*=x)%=MOD;        }        (x*=x)%=MOD;        y>>=1;    }    return re;}int main(){    int i,j;    f[1]=g[1]=1;    for(i=2;i<MAXN;i++){        f[i]=(f[i-1]+f[i-2])%MOD;        g[i]=f[i];    }    g[0]=ng[0]=1;    for(i=1;i<MAXN;i++){        ng[i]=mi(g[i],MOD-2);        for(j=i+i;j<MAXN;j+=i){            (g[j]*=ng[i])%=MOD;        }        (g[i]*=g[i-1])%=MOD;        (ng[i]*=ng[i-1])%=MOD;    }    int tmp;    scanf("%d",&tmp);    while(tmp--){        ll ans=1;        scanf("%d%d",&n,&m);        if(n>m){            swap(n,m);        }        for(i=1;i<=n;i++){            int ti=min(n/(n/i),m/(m/i));            (ans*=mi(g[ti]*ng[i-1]%MOD,(ll)(n/i)*(m/i)))%=MOD;            i=ti;        }        printf("%lld\n",ans);    }    return 0;}/**/
0 0