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

  题目链接

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

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

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

  可以变换一下

  $prodlimits_{w=1}^{min(n,m)}f[w]^{sumlimits_{i=1}^{n}sumlimits_{j=1}^{m}[gcd(i,j)==w]}$

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

  变为$prodlimits_{w=1}^{min(n,m)}f[w]^{sumlimits_{w|d}mu(frac{d}{w})frac{n}{d}frac{m}{d}}$

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

  然后枚举T=dw

  指数变为$sumlimits_{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
",ans);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/cellular-automaton/p/8685582.html