【Luogu】P3704数字表格(莫比乌斯反演+大胆暴力)

  题目链接

  给你们讲个笑话:Konoset是个sb,他快速幂的时候把幂次取模了。

  原式差不多就是这样吧$\prod\limits_{i=1}^{n}\prod\limits_{j=1}^{m}f[gcd(i,j)]$

  然后我们枚举gcd(i,j)

  可以变换一下

  $\prod\limits_{w=1}^{min(n,m)}f[w]^{\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}[gcd(i,j)==w]}$

  然后上面那个玩意搞搞可以反演一下

  变为$\prod\limits_{w=1}^{min(n,m)}f[w]^{\sum\limits_{w|d}\mu(\frac{d}{w})\frac{n}{d}\frac{m}{d}}$

  上面那个玩意显然=$\sum\limits_{d}\mu(d)\frac{n}{dw}\frac{m}{dw}$

  然后枚举T=dw

  指数变为$\sum\limits_{\frac{T}{w}}\mu(\frac{T}{w})\frac{n}{T}\frac{m}{T}$

  然后把上面那个cigma搬到下面来

  变成累乘

  然后改成枚举T,中间预处理前缀积后面n除以Tm除以T的部分数论分块

  这题是真的恶心

  

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cctype>
#define maxn 1000020
#define mod 1000000007
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

long long fib[maxn];
long long sum[maxn];
long long mul[maxn];
long long ni[maxn];
int miu[maxn];
bool vis[maxn];
int prime[maxn],num;

long long pow(long long n,long long x){
    long long ans=1;
    while(x){
        if(x&1)    ans=(ans*n)%mod;
        n=(n*n)%mod;
        x>>=1;
    }
    return ans;
}

int main(){
    fib[0]=0;fib[1]=vis[0]=vis[1]=miu[1]=1;
    for(int i=2;i<maxn;++i){
        if(vis[i]==0){
            prime[++num]=i;
            miu[i]=-1;
        }
        for(int j=1;j<=num&&i*prime[j]<maxn;++j){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)    break;
            miu[i*prime[j]]=-miu[i];
        }
    }
    for(int i=2;i<maxn;++i){
        fib[i]=(fib[i-1]+fib[i-2])%mod;
        sum[i]=1;
    }
    sum[1]=1;
    for(int i=1;i<maxn;++i){
        long long now=fib[i],ret=pow(now,mod-2);
        for(register int j=i;j<maxn;j+=i){
            if(miu[j/i]==1)    sum[j]=(sum[j]*now)%mod;
            else            sum[j]=(sum[j]*ret)%mod;
        }
    }
    mul[1]=sum[1];mul[0]=1;ni[0]=ni[1]=1;
    for(int i=2;i<maxn;++i){
        mul[i]=(sum[i]*mul[i-1])%mod;
        ni[i]=pow(mul[i],mod-2);
    }
    int T=read();
    while(T--){
        long long n=read(),m=read();
        int l=1;long long ans=1;int top=min(n,m);
        while(l<=top){
            int r=min(n/(n/l),m/(m/l));
            ans*=pow(mul[r]*ni[l-1]%mod,(n/l)*(m/l));
            ans%=mod;
            l=r+1;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

  

posted @ 2018-04-01 09:14  Konoset  阅读(181)  评论(0编辑  收藏  举报