zoukankan      html  css  js  c++  java
  • 容斥原理算法总结(bzoj 2986 2839)

    容斥原理是一个从小学就开始学习的算法。但是很多难题现在都觉得做的十分吃力。

    容斥原理大概有两种表现形式,一种是按照倍数进行容斥,这个东西直接用莫比乌斯函数就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define MAXN 200100
    typedef long long qword;
    bool pflag[MAXN];
    int prime[MAXN],topp=-1;
    int mu[MAXN];
    int a[MAXN],tota;
    int b[MAXN],totb;
    void init()
    {
            for (register int i=2;i<MAXN;i++)
            {
                    if (!pflag[i])
                    {
                            prime[++topp]=i;
                            mu[i]=1;
                    }
                    for (register int j=0;j<=topp && i*prime[j]<MAXN;j++)
                    {
                            pflag[i*prime[j]]=true;
                            if (i%prime[j]==0)
                            {
                                    mu[i*prime[j]]=0;
                                    break;
                            }
                            mu[i*prime[j]]=-mu[i];
                    }
            }
    }
    
    int main()
    {
            //freopen("input.txt","r",stdin);
            qword tot;
            scanf("%lld
    ",&tot);
            init();
            for (register int i=1;i<MAXN;i++)
                    if (mu[i]==1)
                            a[tota++]=i;
                    else if (mu[i]==-1)
                            b[totb++]=i;
            register qword l,r,mid;
            register qword ans=0;
            l=0,r=26000000000LL;
            while (l+1<r)
            {
                    mid=(l+r)>>1;
                    ans=0;
                    for (register int i=0;i<tota && (qword)a[i]*a[i]<=mid;i++)
                            ans=ans+mid/((qword)a[i]*a[i]);
                    for (register int i=0;i<totb && (qword)b[i]*b[i]<=mid;i++)
                            ans=ans-mid/((qword)b[i]*b[i]);
                    if (ans>=tot)
                            r=mid;
                    else
                            l=mid;
            }
            printf("%lld
    ",r);
            
    }
    bzoj 2986

    另一种可以理解为一个一个递推,按照+/-1容斥。

      bzoj 2839 : 一个有N个元素的集合有2^N个不同子集(包含空集),现在要在这2^N个集合中取出若干集合(至少一个),使得它们的交集的元素个数为K,求取法的方案数,答案模1000000007。(是质数喔~)

      这道题虽然说懂了正解,但是还是没有弄清楚最初的做法为什么错了。

      考虑求大于等于i的方案数,可理解为从n个选出i个,再在另n-i个里面任意选择,由于答案的k个肯定属于这i个,所以容斥时再乘上系数C(i,k),直接容斥即可。

      这种题如果方法有问题其实是很难检查出来的,最好的方法是写暴力或者用另一种思路写。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define MAXN 1000100
    #define MOD 1000000007
    typedef long long qword;
    qword fact[MAXN];
    qword pow_mod(qword x,qword y)
    {
            qword ret=1;
            while (y)
            {
                    if (y&1)
                            ret=ret*x%MOD;
                    x=x*x%MOD;
                    y>>=1;
            }
            return ret;
    }
    qword finv[MAXN];
    #define C(x,y) (fact[x]*finv[y]%MOD*finv[(x)-(y)]%MOD)
    
    int main()
    {
            freopen("input.txt","r",stdin);
            int n,m;
            scanf("%d%d",&n,&m);
            fact[0]=1;
            for (register int i=1;i<=n;i++)
                    fact[i]=fact[i-1]*i%MOD;
            finv[n]=pow_mod(fact[n],MOD-2);
            for (register int i=n-1;i>=0;i--)
                    finv[i]=finv[i+1]*(i+1)%MOD;
            register qword ans=0;
            register qword tmp=2;
            ans+=((n-m)%2==0?1:-1)*C(n,n)*tmp%MOD*C(n,m)%MOD;
            for (register int i=n-1;i>=m;i--)
            {
                    tmp=tmp*tmp%MOD;
                    ans+=((i-m)%2==0?1:-1)*C(n,i)*tmp%MOD*C(i,m)%MOD;
                    ans%=MOD;
            }
            //ans=h[m]*C(n,m);
            printf("%lld
    ",ans);
    }
    bzoj 2839

      bzoj 1042:硬币购物一共有4种硬币。面值分别为c1,c2,c3,c4。某人去商店买东西,去了tot次。每次带di枚ci硬币,买si的价值的东西。请问每次有多少种付款方法。

      很早以前做的一道经典题目,其思路很有借鉴意义。

     

  • 相关阅读:
    Java并发编程的艺术(二)——volatile、原子性
    Java并发编程的艺术(一)——并发编程的注意问题
    算法——朋友圈(并查集)
    算法——汉诺塔问题
    算法——接雨水
    算法——n皇后问题
    深入理解Java虚拟机(八)——类加载机制
    深入理解Java虚拟机(七)——类文件结构
    转-项目管理5阶段|一位高级项目经理的4年项目经验分享
    什么是信息系统项目管理师(高级项目经理)
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4390949.html
Copyright © 2011-2022 走看看