洛谷 P3704 [SDOI2017]数字表格 莫比乌斯反演

大意:
设f[i]为斐波那契数列的第i项,其中f[1]=1,f[2]=1。
给一个N*M的表格,[i,j]的数字为f[gcd(i,j)],求表格中的数积,对1e9+7取模。

分析:莫比乌斯反演题,和于神之怒有点像。

题解

代码:

// luogu-judger-enable-o2
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long

const LL mod=1000000007;
const LL maxn=1e6+7;

using namespace std;

LL T,n,m,cnt;
LL mul[maxn];
LL prime[maxn],not_prime[maxn];
LL fib[maxn],g[maxn],rev[maxn];

LL power(LL x,LL y)
{
    if (y==0) return 1;
    if (y==1) return x;
    LL c=power(x,y/2);
    c=(c*c)%mod;
    if (y%2==1) c=(c*x)%mod;
    return c;
}

void getmul(LL n)
{
    mul[1]=1;
    for (LL i=2;i<=n;i++)
    {
        if (!not_prime[i])
        {
            prime[++cnt]=i;
            mul[i]=-1;
        }
        for (LL j=1;j<=cnt;j++)
        {
            if (i*prime[j]>n) break;
            not_prime[i*prime[j]]=1;
            if (i%prime[j]==0)
            {
                mul[i*prime[j]]=0;
                break;
            }
            mul[i*prime[j]]=-mul[i];
        }
    }
    fib[0]=0; fib[1]=1;
    g[1]=1; rev[1]=1;
    for (LL i=2;i<=n;i++)
    {
        g[i]=1;
        fib[i]=(fib[i-1]+fib[i-2])%mod;
        rev[i]=power(fib[i],mod-2);
    }   
    for (LL i=1;i<=n;i++)
    {           
        if (!mul[i]) continue;
        LL x;
        for (LL j=i;j<=n;j+=i)
        {
             if (mul[i]==1) x=fib[j/i];
                       else x=rev[j/i];
             g[j]=(g[j]*x)%mod;
        }
    }
    g[0]=1;
    for (LL i=2;i<=n;i++) g[i]=(g[i]*g[i-1])%mod;
}

LL calc(LL n,LL m)
{
    if (n>m) swap(n,m);
    LL ans=1;
    for (LL i=1,last;i<=n;i=last+1)
    {
        last=min(n/(n/i),m/(m/i));
        ans=ans*(power(g[last]*power(g[i-1],mod-2)%mod,(n/i)*(m/i)%(mod-1)))%mod;
    }
    return ans;
}

int main()
{
     scanf("%lld",&T);       
     getmul(maxn);   
     while (T--)
     {
         scanf("%lld%lld",&n,&m);
         printf("%lld\n",calc(n,m));
     }
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/80245914