山东OI2017-数字表格

O(n^2)——–>O(nlogn)
莫比乌斯、枚举约数
注意:逆元

#include 
using namespace std;
typedef long long LL;
const int mod = 1000000007;
const int N = 1000000;
const int mx = 1000010;
int prime[80000],mu[mx],n,m,tot,ans;
int sf[mx],fib[mx],invf[mx],sg[mx],g[mx],invg[mx];
bool nop[mx];
int fun(int n,int k) {
    LL s=1;
    while (k) {
        if (k&1) s=s*n%mod;
        n=1LL*n*n%mod;
        k>>=1;
    }
    return (int)s;
}
int main() {
    mu[1]=fib[1]=fib[2]=sf[1]=g[1]=1;
    for (LL i=2; i<=N; ++i) {
        if (!nop[i]) {
            prime[tot++]=i;
            mu[i]=-1;
        }
        for (LL j=0; jif (i*prime[j]>N) break;
            nop[i*prime[j]]=true;
            if (i%prime[j]==0) {
                mu[i*prime[j]]=0;
                break;
            } else mu[i*prime[j]]=-mu[i];
        }
        fib[i]=fib[i-1]+fib[i-2];
        if (fib[i]>=mod) fib[i]-=mod;
        sf[i]=1LL*sf[i-1]*fib[i]%mod;
        g[i]=1;
    }

    sg[1]=invg[0]=invg[1]=invf[0]=invf[1]=1;
    invf[N]=fun(sf[N],mod-2);
    for (int i=N; i>=2; --i)
        invf[i-1]=1LL*invf[i]*fib[i]%mod,
                  invf[i]=1LL*invf[i]*sf[i-1]%mod;
    for (int i=2; i<=N; ++i) {
        for (int j=1; i*j<=N; ++j)
            if (mu[j]==1)
                g[i*j]=1LL*g[i*j]*fib[i]%mod;
            else if (mu[j]==-1)
                g[i*j]=1LL*g[i*j]*invf[i]%mod;
        sg[i]=1LL*sg[i-1]*g[i]%mod;
    }
    invg[N]=fun(sg[N],mod-2);
    for (int i=N; i>=2; --i) invg[i-1]=1LL*invg[i]*g[i]%mod;

    int T;
    scanf("%d",&T);
    while (T--) {
        scanf("%d%d",&n,&m);
        if (n>m) swap(n,m);
        ans=1;
        for (int last,i=1; i<=n; i=last+1)
            last=min(n/(n/i),m/(m/i)),
            ans=1LL*ans*fun(1LL*sg[last]*invg[i-1]%mod,1LL*(n/i)*(m/i)%(mod-1))%mod;
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(数论)