• [bzoj4816][Sdoi2017]数字表格 (反演+逆元)


    (真不想做莫比乌斯了)

    首先根据题意写出式子

    i=1~nj=1~m)f[gcd(i,j)]

    很明显的f可以预处理出来,解决

    根据套路分析,我们可以先枚举gcd(i,j)==d

    (d=1~n)f[d]......后面该怎么写?

    我们发现前面式子中i,j为连乘,而对于相同的gcd,就可以变成f[d]的几次幂!

    则∏(d=1~n)f[d]Σ(i=1~n/d)Σ(j=1~m/d)[gcd(i,j)==1]

    然后就可以开心的反演了

    (d=1~n)f[d]Σ(i=1~n/d)Σ(j=1~m/d)[gcd(i,j)==1]

    =∏(d=1~n)f[d]Σ(i=1~n/d)Σ(j=1~m/d)Σ(k|i&&k|j)μ(k)

    (接下来,我们先枚举k)

    =∏(d=1~n)f[d]Σ(k=1~n)μ[k](n/kd)(m/kd)

    (先枚举kd=D)

    =∏(D=1~n)(d|D)f[d]μ[D/d](n/D)(m/D)

    =∏(D=1~n)(∏(d|D)f[d]μ[D/d])(n/D)(m/D)

    至此反演结束

    再来观察这个式子,我们发现∏(d|D)f[d]μ[D/d]是关于D的一个函数,我们可以把它的前缀积处理出来,复杂度O(n*log(n))

    处理过程中,当μ[D/d]==-1时需要除法,所以需要求逆元,而对于1e9+7这个素数,f[i]对于1e9+7的逆元为pow(f[i],mod-2)

    在求解时我们需要取一段的前缀积,所以还需要把前缀积的逆元处理出来,方法同上

    逆元处理复杂度O(n*log(n))

    在求解时结合数论分块和快速幂,复杂度O(T*sqrt(n)*log(n))

    总复杂度O(n*log(n)+T*sqrt(n)*log(n))

    这道题做的时候主要卡在把变成Σ并变成指数,在此做个标记

     

    AC代码

    #include<cstdio>
    #include<iostream>
    #define ll long long
    #define re register
    const int mod=1e9+7;
    using namespace std;
    int p[500010],top;bool v[1000010];short mu[1000010];ll f[1000010],ni[1000010],tot[1000010];
    inline ll pow(ll a,ll b){
        re ll ans=1;
        for(;b;b>>=1){
            if(b&1) (ans*=a)%=mod;
            (a*=a)%=mod;
        }
        return ans;
    }
    int main(){
        mu[1]=1;f[1]=1;ni[1]=1;tot[1]=1;
        for(int i=2;i<=1000000;i++)
          f[i]=(f[i-1]+f[i-2])%mod,ni[i]=pow(f[i],mod-2),tot[i]=1;
        for(int i=2;i<=1000000;i++){
            if(!v[i]){
                p[++top]=i;
                mu[i]=-1;
            }
            for(int j=1;j<=top&&p[j]*i<=1000000;j++){
                v[i*p[j]]=1;
                if(!(i%p[j])) break;
                mu[i*p[j]]=-mu[i];
            }
        }
        for(int i=1;i<=1000000;i++){
            for(re int j=1;j*i<=1000000;j++)
              if(mu[j]==-1) (tot[j*i]*=ni[i])%=mod;
              else if(mu[j]==1) (tot[j*i]*=f[i])%=mod;
        }
        tot[0]=1;
        for(int i=1;i<=1000000;i++) (tot[i]*=tot[i-1])%=mod;
        ni[0]=1;
        for(re int i=1;i<=1000000;i++)
          ni[i]=pow(tot[i],mod-2);
        re int t,n,m,x;
        re ll ans;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);ans=1;
            if(n>m) swap(n,m);
            for(int i=1;i<=n;i=x+1){
                x=min((n/(n/i)),(m/(m/i)));
                (ans*=pow(tot[x]*ni[i-1]%mod,1ll*(n/i)*(m/i)))%=mod;
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
    View Code

     

    ${color{Teal} 只}$${color{Teal} 是}$${color{Teal} 拼}$${color{Teal} 凑}$${color{Teal} 出}$${color{Teal} 与}$${color{Teal} 你}$${color{Teal} 在}$${color{Teal} 一}$${color{Teal} 起}$${color{Teal} 的}$${color{Teal} 时}$${color{Teal} 间}$
  • 相关阅读:
    go多平台编译打包
    正则表达式
    Java 线程安全问题的本质
    Thread interrupt() 线程中断的详细说明
    git -c diff.mnemonicprefix=false -c core.quotepath=false --no-optional-locks push -v --tags origin master:master Logon failed, use ctrl+c to cancel basic credential prompt.
    kafka 消费组功能验证以及消费者数据重复数据丢失问题说明 3
    kafka 副本机制和容错处理 -2
    Mat使用详解
    MySql Binlog 说明 & Canal 集成MySql的更新异常说明 & MySql Binlog 常用命令汇总
    ElasticSearch 集群基本概念及常用操作汇总(建议收藏)
  • 原文地址:https://www.cnblogs.com/mikufun-hzoi-cpp/p/11013959.html
Copyright © 2020-2023  润新知