容斥原理级笔记

容斥原理:

| s1 ⋃ s2 ⋃ s3 …… ⋃ sn | = | s1 |+ | s2 | + …… | s3 | - | s1 ⋂ s2 | -  …… + | s1 ⋂ s2 ⋂ s3 | + ……

应用一(基础):

AcWing能被整除的数

思路:

(1)容斥原理的直接应用。首先将所有能被其中任意一个p[i]整除的数的个数加上,再减去所有能被其中任意两个p[i]整除的数的个数,再加上所有能被其中任意三个p[i]整除的数的个数,一次类推......

(2)借助二进制代表是否需要满足次条件,此二进制为1代表需要满足,为0则不需要满足

(3)根据奇偶性判断此数为加还是减(奇为加,偶为减)

code:

#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int maxn=20;
int n,m,p[maxn],ans;

int main(){
//    freopen("123.in","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=0;i>j&1){
                cnt++;
                if((ll)sum*p[j]>n){
                    sum=-1;
                    break;
                }
                sum*=p[j];
            }
        }
        if(sum!=-1){
            if(cnt%2){
                ans+=n/sum;
            }
            else ans-=n/sum;
        }
    }
    printf("%d\n",ans);
    return 0;
}

应用二(中等):

214. Devu和鲜花 - AcWing题库

思路:

(1)首先考虑理想状态下,在每一组里面都可以去无限多花,用隔板法考虑,初始x1+x2+x3+... ...+xn=M(即在每组里面取的花的数量,xi>=0),令yi=xi+1,则y1+y2+y3+... ...+yn=M+N \left (yi>=1 \right )所以方案数为:在M+N−1空隙中插入N−1个板,使其分成N组,即C\binom{N-1}{M+N-1}

(2)其次在题目要求的情况下,需满足x1<=A1,x2<=A2,x3<=A3 , ... ... ,xn<=An,

正难则反,答案为:C\binom{N-1}{M+N-1} - \left | S1 \cup S2 \cup S3 \cup ... ... \cup Sn \right | 即 C\binom{N-1}{M+N-1} - \left | S1 \right | - \left | S2 \right | - ... ... + - \left | S1 \cap S2 \right |+... ... - \left | S1\cap S2 \cap S3 \right | -... ....

(3)其中Si即为满足第i个条件的方案数:在第i组内至少取出 Ai+1 朵花,那么此时还剩 M -(Ai+1)朵花,方案数为C\binom{N-1}{M+N-1 -\left ( Ai+1 \right )} 【代表的是\left | Si \right | 】

(4)以此类推,\left | Si \cap Sj\right | = C\binom{N-1}{M+N-1 -\left ( Ai+1 \right ) -\left ( Aj+1 \right )}

code:

#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int N=30,mod=1e9+7;
ll n,m,down=1;
ll A[N];

int qwi(int a,int k){
    int res=1;
    while(k){
        if(k&1) res=(ll)res*a%mod;
        a=(ll)a*a%mod;
        k>>=1;
    }
    return res%mod;
}

int C(ll a,ll b){
    if(aa-b;i--) up=i%mod*up%mod;

    return (ll)up*down%mod;
}

int main(){
//    freopen("123.in","r",stdin);
    scanf("%lld%lld",&n,&m);
    for(int i=0;i>j&1){
                sign*=-1;
                a-=A[j]+1;
            }
        }
        ans=(ans+C(a,b)*sign)%mod;
    }
    printf("%d\n",(ans+mod)%mod);
    return 0;
}

应用三(较难):

215. 破译密码 - AcWing题库

思路:

(1)首先了解莫比乌斯函数,详情见莫比乌斯函数_Galaxy_Su的博客-CSDN博客

(2)了解整除分块

(3)优秀题解:AcWing 215. 破译密码题解 - AcWing

code:

#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int N=5e4+20;

int primes[N],cnt;
bool vis[N];
int mobius[N],sum[N];

void Mobius(int n){
    mobius[1]=1;
    for(int i=2;i<=n;i++){
        if(!vis[i]){
            primes[cnt++]=i;
            mobius[i]=-1;
        }
        for(int j=0;primes[j]*i<=n;j++){
            int t=primes[j]*i;
            vis[t]= true;
            if(i%primes[j]==0){
                mobius[t]=0;
                break;
            }
            mobius[t]=mobius[i]*-1;
        }
    }
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+mobius[i];
    }
}

int main(){
//    freopen("123.in","r",stdin);
    Mobius(N-1);
    int t;
    scanf("%d",&t);
    while(t--){
        int a,b,d;
        scanf("%d%d%d",&a,&b,&d);
        a/=d,b/=d;
        int n=min(a,b);
        ll ans=0;
        for(int l=1,r;l<=n;l=r+1){
            r=min(n,min(a/(a/l),b/(b/l)));
            ans+=(sum[r]-sum[l-1])*(ll)(a/l)*(b/l);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

(会持续更新)

你可能感兴趣的:(算法,算法)