累乘函数线性逆元打表,阶乘反演——bzoj4816

Posted zsben991126

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了累乘函数线性逆元打表,阶乘反演——bzoj4816相关的知识,希望对你有一定的参考价值。

学了一种新套路,倒序打表函数的逆元可以直接线性完成

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define LL long long
const long long mod = 1e9+7;
#define maxn 1000001

LL Pow(LL a,LL b)
    if (!b)
        return 1LL;
    LL x=Pow(a,b/2);
    x=x*x%mod;
    if (b&1LL)
        x=x*a%mod;
    return x;

/*ll Pow(ll a,ll b)
    ll res=1;
    while(b)
        if(b%2)
            res=res*a%mod;
        b>>=1;a=a*a%mod;
    
    return res;
*/
ll n,m;
ll F[maxn],pre[maxn],invF[maxn];
void init1()
    F[0]=0;F[1]=1;
    for(int i=2;i<maxn;i++)
        F[i]=(F[i-1]+F[i-2])%mod;
    pre[0]=1;
    for(int i=1;i<maxn;i++)//临时数组算累乘 
        pre[i]=pre[i-1]*F[i]%mod;

    ll tmp=Pow(pre[maxn-1],mod-2);
    for(int i=maxn-1;i>=1;i--)
        invF[i]=tmp*pre[i-1]%mod,tmp=tmp*F[i]%mod;


bool vis[maxn];
ll prime[maxn],mm,mu[maxn];
void init2()
    mu[1]=1; 
    for(int i=2;i<maxn;i++)
        if(!vis[i])
            mu[i]=-1;
            prime[++mm]=i;
        
        for(int j=1;j<=mm;j++)
            if(i*prime[j]>=maxn)break;
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
                mu[i*prime[j]]=0;
                break;
            
            else mu[i*prime[j]]=-mu[i];
        
    


ll mul[maxn],invmul[maxn],g[maxn];
void init3()
    for(int i=1;i<maxn;i++)g[i]=1;
    for(int i=1;i<maxn;i++)
        for(int j=1;j*i<maxn;j++)
            if(mu[j]==1)
                g[i*j]=g[i*j]*F[i]%mod;
            else if(mu[j]==-1)
                g[i*j]=g[i*j]*invF[i]%mod;
        
    mul[0]=1;
    for(int i=1;i<maxn;i++)    
        mul[i]=mul[i-1]*g[i]%mod;
    invmul[maxn-1]=Pow(mul[maxn-1],mod-2);
    for(int i=maxn-2;i>=0;i--)
        invmul[i]=invmul[i+1]*g[i+1]%mod;


int main()
    int t;cin>>t;
    init1();
    init2();
    init3();
    while(t--)
        cin>>n>>m;
        if(n>m)swap(n,m);
        ll ans=1;
        for(int l=1,r;l<=n;l=r+1)
            r=min(n/(n/l),m/(m/l));
            ll tmp=mul[r]*invmul[l-1]%mod;
            ans=ans*Pow(tmp,(n/l)*(m/l)%(mod-1))%mod;
        
        cout<<ans<<\n;
    

 

以上是关于累乘函数线性逆元打表,阶乘反演——bzoj4816的主要内容,如果未能解决你的问题,请参考以下文章

逆元打表

HDU 6333 莫队分块 + 逆元打表求组合数

线性求逆元 组合数

BZOJ4816数字表格(莫比乌斯反演)

BZOJ4816: [Sdoi2017]数字表格

[BZOJ4816][SDOI2017]数字表格(莫比乌斯反演)