zoukankan      html  css  js  c++  java
  • hdu 6053: TrickGCD (2017 多校第二场 1009) 【莫比乌斯 容斥原理】

    题目链接

    定义f[n]表示n是最大公约数情况下的计数,F[n]为n是公约数情况下的计数

    (可以和 http://www.cnblogs.com/Just--Do--It/p/7197788.html hdu1695 进行类比)

    显然F[n]和f[n]是满足下面这个关系的

    所以,可以用下面这个公式求解f[n]

      

    得到下面的AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    #define max(a,b) ((a)>(b)? (a):(b))
    #define min(a,b) ((a)<(b)? (a):(b))
    
    const int maxn=1e5+7;
    int prime[maxn+5];
    bool check[maxn+5];
    int mu[maxn+5];
    
    void init()
    {
        mu[1]=1;
        int tot=0;
        for(int i=2;i<=maxn;i++)
        {
            if(!check[i])
            {
                prime[tot++]=i;
                mu[i]=-1;
            }
            for(int j=0;j<tot;j++)
            {
                if(i*prime[j]>maxn) break;
                check[i*prime[j]]=true;
                if(i%prime[j]==0)
                {
                    mu[i*prime[j]]=0;
                    break;
                }
                else
                {
                    mu[i*prime[j]]=-mu[i];
                }
            }
        }
    }
    
    const int N=1e5+5;
    const int mod=1e9+7;
    
    int n;
    int num[2*N];
    LL F[N];
    LL f[N];
    
    
    LL qpow(LL x,LL n)
    {
        LL ret=1;
        for(;n;n>>=1)
        {
            if(n&1) ret=ret*x%mod;
            x=x*x%mod; 
        }
        return ret;
    }
    
    int main()
    {
        init();
        int T; 
        scanf("%d",&T);
        for(int kase=1;kase<=T;kase++)
        {
            memset(num,0,sizeof(num));
            memset(f,0,sizeof(f));
            int max_gcd=1e9,max_a=0;
            LL ans=0;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                int t;
                scanf("%d",&t);
                num[t]++;
                max_gcd=min(t,max_gcd);
                max_a  =max(t,max_a  );
            }
            for(int i=1;i<2*N;i++)
                num[i]+=num[i-1];
            for(int i=2;i<=max_gcd;i++)
            {
                F[i]=1;
                for(int j=i;j<=max_a;j+=i)
                    F[i]=F[i]*qpow(j/i,num[j+i-1]-num[j-1])%mod;
            }
    //        =================================
            for(int i=2;i<=max_gcd;i++)
                for(int j=1;i*j<=max_gcd;j++)
                    f[i]=(f[i]+mu[j]*F[i*j])%mod;
            for(int i=2;i<=max_gcd;i++)
                ans=(ans+f[i])%mod;
    //        =================================
            printf("Case #%d: %lld
    ",kase,ans); 
        }
    }

    然而!=====所夹的部分可以用一行代码代替!!!!虽然运行时间不会减少多少,不过代码量上优化了很多!

    不过这种写法的实质其实可以从容斥原理的角度来考虑,再借用了莫比乌斯函数的性质。

    定义:  性质Pi表示i是对象x的一个质因数,  集合Ai表示具有性质Pi的对象的集合

    比较容易想到,所有可能的公因数对应的对象计数之和,恰为所有集合的并 中的对象的总个数

    那么用容斥原理求 所有集合的并 中的对象的总个数时,奇数个基本集合的交前面的系数是正一,偶数个的是负一。并且,n的因数中包含质因数平方的F[n]在这里面是不需要被计数的。

    这样恰好就与莫比乌斯函数的性质产生了联系。

    参考博客:  http://blog.csdn.net/acterminate/article/details/76216345

    也就变成了

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    #define max(a,b) ((a)>(b)? (a):(b))
    #define min(a,b) ((a)<(b)? (a):(b))
    
    const int maxn=1e5+7;
    int prime[maxn+5];
    bool check[maxn+5];
    int mu[maxn+5];
    
    void init()
    {
        mu[1]=1;
        int tot=0;
        for(int i=2;i<=maxn;i++)
        {
            if(!check[i])
            {
                prime[tot++]=i;
                mu[i]=-1;
            }
            for(int j=0;j<tot;j++)
            {
                if(i*prime[j]>maxn) break;
                check[i*prime[j]]=true;
                if(i%prime[j]==0)
                {
                    mu[i*prime[j]]=0;
                    break;
                }
                else
                {
                    mu[i*prime[j]]=-mu[i];
                }
            }
        }
    }
    
    const int N=1e5+5;
    const int mod=1e9+7;
    
    int n;
    int num[2*N];
    LL F[N];
    LL f[N];
    
    
    LL qpow(LL x,LL n)
    {
        LL ret=1;
        for(;n;n>>=1)
        {
            if(n&1) ret=ret*x%mod;
            x=x*x%mod; 
        }
        return ret;
    }
    
    int main()
    {
        init();
        int T; 
        scanf("%d",&T);
        for(int kase=1;kase<=T;kase++)
        {
            memset(num,0,sizeof(num));
            memset(f,0,sizeof(f));
            int max_gcd=1e9,max_a=0;
            LL ans=0;
            scanf("%d",&n);
            for(int i=0;i<n;i++)
            {
                int t;
                scanf("%d",&t);
                num[t]++;
                max_gcd=min(t,max_gcd);
                max_a  =max(t,max_a  );
            }
            for(int i=1;i<2*N;i++)
                num[i]+=num[i-1];
            for(int i=2;i<=max_gcd;i++)
            {
                F[i]=1;
                for(int j=i;j<=max_a;j+=i)
                    F[i]=F[i]*qpow(j/i,num[j+i-1]-num[j-1])%mod;
    //            printf("F[%d]=%4lld
    ",i,F[i]);
                ans=(ans-mu[i]*F[i]+mod)%mod;
            }
            printf("Case #%d: %lld
    ",kase,ans); 
        }
    }
  • 相关阅读:
    MD5验签同一字符串得到不同的MD5签名值可能问题之一
    Git本地仓库与远程github同步的时候提示fatal: remote origin already exists 错误解决办法
    SVN Error: Unreadable path encountered; access denied;
    2018年终个人总结
    ant编译无法依赖rt.jar
    ORA-00980: 同义词转换不再有效
    二叉树的深度和广度优先遍历
    Missing HTTP Strict-Transport-Security Header (HSTS) 解决
    单例模式
    sql 替换字段中部分内容
  • 原文地址:https://www.cnblogs.com/Just--Do--It/p/7247389.html
Copyright © 2011-2022 走看看