习题:数字表格(莫比乌斯反演)

题目

传送门

思路

首先,我们应该转换一下思路

对于每一个\(f_{i}\),我们求出他的贡献是多少

\(ans=\prod_{d=1}^{n}f(i)^{\sum_{i=1}^{\frac{n}{d}}\sum_{i=1}^{\frac{m}{d}}[gcd(i,j)=1]}\)

首先我们考虑

\(\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[gcd(i,j)=1]\)

这后面一个就是莫比乌斯反演的老套路了,直接套上\(\mu\)

这里假设\(n>m\)

\(\begin{aligned}\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}[gcd(i,j)=1]&=\sum_{i=1}^{\frac{n}{d}}\sum_{j=1}^{\frac{m}{d}}\sum_{k|gcd(i,j)}\mu(k)\\&=\sum_{i=1}^{\frac{n}{d}}\lfloor\frac{n}{id}\rfloor\lfloor\frac{m}{id}\rfloor\mu(i)\end{aligned}\)

这里就可以直接分块了

据某位迟到早退的巨佬表示可以卡过去

\(t=id\),再带回原式

\(\prod_{t=1}^{n}\prod_{d|t}f(d)^{\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor\mu(\frac{t}{d})}\)

之后我们发现

除了\(\mu(\frac{t}{d})\),剩下两个跟d无关

即我们就可以提出来

\(\prod_{t=1}^{n}(\prod_{d|t}f(d)^{\mu(\frac{t}{d})})^{\lfloor\frac{n}{t}\rfloor\lfloor\frac{m}{t}\rfloor}\)

内层的可以预处理

时间复杂度为\(\sum_{i=1}^{n}\frac{n}{i}\)

其实这就是调和级数

时间复杂度即为\(O(nlog_n)\)

总时间复杂度为\(O(nlog_n+t\sqrt n*log_n)\)

代码

#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
int t;
int n,m;
int lenp;
int mu[1000005];
int pri[1000005];
int inv[1000005];
int r;
long long ans;
long long g[1000005];
long long f[1000005];
bool vis[1000005];
void solve_f()
{
    f[0]=0;
    f[1]=1;
    for(int i=2;i<=1000000;i++)
        f[i]=(f[i-1]+f[i-2])%mod;
}
void sieve()
{
    mu[1]=1;
    for(int i=2;i<=1000000;i++)
    {
        if(!vis[i])
        {
            mu[i]=-1;
            pri[++lenp]=i;
        }
        for(int j=1;j<=lenp&&pri[j]*i<=1000000;j++)
        {
            vis[i*pri[j]]=1;
            if(i%pri[j]==0)
            {
                mu[i*pri[j]]=0;
                break;
            }
            mu[i*pri[j]]=-mu[i];
        }
    }
}
long long qkpow(long long a,int b)
{
    if(b==0)
        return 0;
    if(b==1)
        return a;
    long long t=qkpow(a,b/2);
    t=t*t%mod;
    if(b%2==1)
        t=t*a%mod;
    return t;
}
void prepare()
{
    solve_f();
    sieve();
    for(int i=0;i<=1000000;i++)
    {
        g[i]=1;
        inv[i]=qkpow(f[i],mod-2);
    }
    for(int i=1;i<=1000000;i++)
    {
        for(int j=1;j*i<=1000000;j++)
        {
            if(mu[j]==0)
                continue;
            if(f[i]==0)
                g[i*j]=0;
            else if(mu[j]==1)
                g[i*j]=(g[i*j]*f[i])%mod;
            else
                g[i*j]=(g[i*j]*inv[i])%mod;
        }
    }
    for(int j=2;j<=1000000;j++)
        g[j]=g[j]*g[j-1]%mod;
}
void c_in()
{
    ans=1;
    cin>>n>>m;
    if(n>m)
        swap(n,m);
    for(int l=1;l<=n;l=r+1)
    {
        r=min(n/(n/l),m/(m/l));
        long long tot=g[r]*qkpow(g[l-1],mod-2)%mod;
        ans=ans*qkpow(tot,1ll*(n/l)*(m/l)%(mod-1))%mod;
    }
    cout<<ans<<'\n';
}
int main()
{
    //ios::sync_with_stdio(false);
    prepare();
    cin>>t;
    for(int i=1;i<=t;i++)
        c_in();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/loney-s/p/12790332.html