知识点 - 容斥原理 鸽巢原理 乘法原理

知识点 - 容斥原理 鸽巢原理 乘法原理

解决问题类型:

容斥:算重了。

  1. 首位大于1,末尾小于8的排列数
  2. 长度为n的由 (0, 1, 2) 构成,且0,1,2至少出现一次的子序列个数
  3. n元一次方程整数解个数。
  4. 给定区间互质数对个数
  5. 给n个,问给定区间中是某个 a i a_{i} ai的倍数的个数
  6. 符合给定规则的串的个数
  7. 从一个格子走到另一个格子的方案数
  8. 互质四元组的个数
  9. harmonic triplets的个数
  10. 错排问题

鸽巢:

题目给了n,考虑n+1的情况。

结论

容斥公式

(1)设 A 1 , A 2 , ⋅ ⋅ ⋅ , A n A_{1},A_{2}, \cdot \cdot \cdot ,A_{n} A1,A2,,An是集合 S S S 的子集,表示以集合 S S S 代表可能发生的事件中的 n n n 个子事件, ∣ A i ∣ \left| A_{i} \right| Ai表示子事件 A i A_{i} Ai发生的个数 ( 0 ≤ i ≤ n ) \left( 0 \leq i \leq n \right) (0in),则有
∣ A 1 ∪ A 2 ∪ A 3 ∪ ⋅ ⋅ ⋅ ∪ A n ∣ = ∑ i = 1 n ∣ A i ∣ − ∑ 1 ≤ i &lt; j ≤ n ∣ A i ∩ A j ∣ + ⋅ ⋅ ⋅ + ( − 1 ) n − 1 ∣ A 1 ∩ A 2 ∩ A 3 ∩ ⋅ ⋅ ⋅ ∩ A n ∣ \left| A_{1} \cup A_{2} \cup A_{3} \cup \cdot \cdot \cdot \cup A_{n} \right| = \sum_{i = 1}^{n}\left| A_{i} \right| - \sum_{1 \leq i &lt; j \leq n}^{}\left| A_{i} \cap A_{j} \right| + \cdot \cdot \cdot + \left( - 1 \right)^{n - 1}\left| A_{1} \cap A_{2} \cap A_{3} \cap \cdot \cdot \cdot \cap A_{n} \right| A1A2A3An=i=1nAi1i<jnAiAj++(1)n1A1A2A3An

压缩版:

∣ ⋃ i = 1 n A i ∣ = ∑ ∅ ≠ J ⊆ 1 , 2 , … , n ( − 1 ) ∣ J ∣ − 1 ∣ ⋂ j ∈ J A j ∣ \left|\bigcup_{i=1}^n A_i \right| = \sum_{\emptyset \neq J\subseteq \\{1,2,\ldots ,n\\}} (-1)^{|J|-1}{\Biggl |}\bigcap_{j\in J}A_{j}{\Biggr |} i=1nAi≠=J1,2,,n(1)J1jJAj

概率版:

KaTeX parse error: Expected '}', got '\cal' at position 2: {\̲c̲a̲l̲ ̲P}(A)代表A事件发生的概率。
KaTeX parse error: Expected '}', got '\cal' at position 3: {\̲c̲a̲l̲ ̲P} \left(\bigcu…

补集公式:

(A上面有横线)
∣ A 1 ‾ ∩ A 2 ‾ ∩ A 3 ‾ ∩ ⋅ ⋅ ⋅ ∩ A n ‾ ∣ = S − ∣ A 1 ∪ A 2 ∪ A 3 ∪ ⋅ ⋅ ⋅ ∪ A n ∣ \left| \overset{\overline{}}{A_{1}} \cap \overset{\overline{}}{A_{2}} \cap \overset{\overline{}}{A_{3}} \cap \cdot \cdot \cdot \cap \overset{\overline{}}{A_{n}} \right| = S - \left| A_{1} \cup A_{2} \cup A_{3} \cup \cdot \cdot \cdot \cup A_{n} \right| A1A2A3An=SA1A2A3An

补集版

∣ ⋂ i = 1 n A i ‾ ∣ = ∑ m = 0 n ( − 1 ) m ∑ ∣ X ∣ = m ∣ ⋂ i ∈ X A i ∣ \left|\bigcap_{i=1}^n \overline{A_i}\right|=\sum_{m=0}^n (-1)^m \sum_{|X|=m} \left|\bigcap_{i\in X} A_{i}\right| i=1nAi=m=0n(1)mX=miXAi

集合大小为r版

∣ ⋃ ∣ B ∣ = r [ ⋂ i ∈ B A i ∩ ⋂ j ̸ ∈ B A j ‾ ] ∣ = ∑ m = r n ( − 1 ) m − r ( m r ) ∑ ∣ X ∣ = m ∣ ⋂ i ∈ X A i ∣ \left|\bigcup_{|B|=r}\left[\bigcap_{i \in B} A_i \cap \bigcap_{j \not\in B} \overline{A_j}\right]\right|=\sum_{m=r}^n (-1)^{m-r}\dbinom{m}{r} \sum_{|X|=m} \left|\bigcap_{i \in X} A_{i}\right| B=riBAij̸BAj=m=rn(1)mr(rm)X=miXAi

容斥问题

上面所有公式证明和问题题解戳这里

错排问题

(1)设 D n D_{n} Dn表示 1 , 2 , 3 , ⋅ ⋅ ⋅ , n 1,2,3, \cdot \cdot \cdot ,n 1,2,3,,n这n个数的一个排列的错排个数,有
D n = n ! [ 1 − 1 1 ! + 1 2 ! − 1 3 ! + ⋅ ⋅ ⋅ + ( − 1 ) n 1 n ! ] , D 1 = 0 , D 2 = 1 D_{n} = n!\left\lbrack 1 - \frac{1}{1!} + \frac{1}{2!} - \frac{1}{3!} + \cdot \cdot \cdot + \left( - 1 \right)^{n}\frac{1}{n!} \right\rbrack,D_{1} = 0,D_{2} = 1 Dn=n![11!1+2!13!1++(1)nn!1],D1=0,D2=1

D n = ( n − 1 ) [ D n − 1 + D n − 2 ] , n &gt; 2 D_n=(n-1)[D_{n-1}+D_{n-2}],n&gt;2 Dn=(n1)[Dn1+Dn2],n>2

D n = n D n − 1 + ( − 1 ) n D_n=nD_{n-1}+(-1)^n Dn=nDn1+(1)n

带有禁位的错排问题

(1)n个元素 a 1 , a 2 , a 3 , ⋅ ⋅ ⋅ , a n a_{1},a_{2},a_{3}, \cdot \cdot \cdot ,a_{n} a1,a2,a3,,an带有禁位 X 1 , X 2 , X 3 , ⋅ ⋅ ⋅ , X n X_{1},X_{2},X_{3}, \cdot \cdot \cdot ,X_{n} X1,X2,X3,,Xn的错排数为
P ( X 1 , X 2 , X 3 , ⋅ ⋅ ⋅ , X n ) = n ! − r 1 ( n − 1 ) ! + r 2 ( n − 2 ) ! − ⋅ ⋅ ⋅ + ( − 1 ) k r k ( n − k ) ! + ⋅ ⋅ ⋅ + ( − 1 ) n r n P\left( X_{1},X_{2},X_{3}, \cdot \cdot \cdot ,X_{n} \right) = n! - r_{1}\left( n - 1 \right)! + r_{2}\left( n - 2 \right)! - \cdot \cdot \cdot + \left( - 1 \right)^{k}r_{k}\left( n - k \right)! + \cdot \cdot \cdot + \left( - 1 \right)^{n}r_{n} P(X1,X2,X3,,Xn)=n!r1(n1)!+r2(n2)!+(1)krk(nk)!++(1)nrn
式中 r k r_{k} rk表示有 k k k 个元素在禁位上的个数

复杂度:

例题

HDU2204 容斥:给你一个正整数N,确定在1到N之间有多少个可以表示成M^K(K>1)的数。

分析:小于 N N N M k M^k Mk的个数为 ⌊ N k ⌋ \lfloor \sqrt[k]{N}\rfloor kN 。枚举所有的k的话。显然有东西算重了。(比如1,我们可以每个k都不统计,最后加1)

首先,如果k不是质数 e . g . M k = M p 1 p 2 e.g.M^k=M^{p1p2} e.g.Mk=Mp1p2,则 M k M^k Mk就以 ( M p 1 ) p 2 (M^{p1})^{p2} (Mp1)p2的形式被 ⌊ N p 2 ⌋ \lfloor \sqrt[p_2]{N}\rfloor p2N 统计过了。于是所有和数都不用统计。

其次,我们发现上面的例子里 M k M^k Mk ⌊ N p 1 ⌋ \lfloor \sqrt[p_1]{N}\rfloor p1N ⌊ N p 2 ⌋ \lfloor \sqrt[p_2]{N}\rfloor p2N 都统计了。于是我们做容斥,K包含1个质数-K包含2个质数+3个…

最后,注意到 2 60 &gt; 1 0 18 2^{60}&gt;10^{18} 260>1018所以容斥到三个质数即可,最大的质数取到59。

hdu1205鸽巢:显然的想法题,但不会用鸽巢原理证明。

hdu5525 约数乘积: n = p 1 e 1 ⋅ p 2 e 2 ⋯ p k e k n=p_1^{e_1} \cdot p_2^{e_2} \cdots p_k^{e_k} n=p1e1p2e2pkek对于每个质数,它被乘入答案的次数为 Σ i = 1 i ≤ e i ⋅ d ( n p e ) \Sigma_{i=1}^{i\leq e}i\cdot d(\frac{n}{p^e}) Σi=1ieid(pen),d(n)为因数个数。
∏ i = 1 i ≤ k p i ( Σ j = 1 j ≤ e i j ⋅ d ( n p i e i ) ) \prod_{i=1}^{i\leq k}p_i^{(\Sigma_{j=1}^{j\leq e_i}j\cdot d(\frac{n}{p_i^{e_i}}))} i=1ikpi(Σj=1jeijd(piein))
注意指数上要模p-1,所以不能用除法。对于/2有 2 ∣ ( n + 1 ) n 2|(n+1)n 2(n+1)n 直接把2乘到模数上。对于 ( 1 + e i ) (1+e_i) (1+ei)维护前后缀积。

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
int prime[20]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59};
long long ans,n;
int i;
void dfs(int j,int num,int p){
    if(p==0){
        long long t=pow(n,1.0/num);
        if(pow(t,0.0+num)>n)  t--;
        t--;
        if(t>0)
            //i为奇数则加,否则减
            ans+=t*(i&1?1:-1);
        return ;
    }
    if(j>=17)
        return;//超出60以内素数,不予考虑
    if(num*prime[j]<60) //仍在范围内,继续搜
        dfs(j+1,num*prime[j],p-1);
    dfs(j+1,num,p);
}
int main(){
    while(scanf("%I64d",&n)!=EOF){
        ans=0;
        for(i=1;i<=3;i++)
            dfs(0,1,i);
        printf("%I64d\n",ans+1);
    }
    return 0;
 
}
//T2
const int N=2e5+10,M=4e6+10,inf=2147483647;
const ll INF=1e18+10,mod=1e9+7;

///   数组大小
int prime(int n)
{
    if(n<=1)
    return 0;
    if(n==2)
    return 1;
    if(n%2==0)
    return 0;
    int k, upperBound=n/2;
    for(k=3; k<=upperBound; k+=2)
    {
        upperBound=n/k;
        if(n%k==0)
            return 0;
    }
    return 1;
}

vector<int>p;
int si[N];
void init()
{
    for(int i=2;i<=100000;i++)
        if(prime(i))
        p.push_back(i);
}
ll quick(ll a,ll b,ll c)
{
    ll ans=1;
    while(b)
    {
        if(b&1)ans=(ans*a)%c;
        b>>=1;
        a=(a*a)%c;
    }
    return ans;
}
int main()
{
    init();
    int n;
    while(~scanf("%d",&n))
    {
        memset(si,0,sizeof(si));
        for(int i=1;i<=n;i++)
        {
            int z;
            int x=i;
            scanf("%d",&z);
            for(int j=0;j<p.size();j++)
            {
                if(1LL*p[j]*p[j]>x)break;
                if(x==1)break;
                while(x%p[j]==0)
                {
                    si[j]+=z;
                    si[j]=(si[j])%(2*(mod-1));
                    x/=p[j];
                }
            }
            if(x!=1)
            {
                int pos=lower_bound(p.begin(),p.end(),x)-p.begin();
                si[pos]+=z;
            }
        }
        ll sum=1;
        for(int i=0;i<p.size();i++)
        {
            sum*=(si[i]+1);
            sum%=(2*(mod-1));
        }
        //cout<<sum<<endl;
        ll ans=1;
        for(int i=0;i<p.size();i++)
        {
            ans=(ans*quick(p[i],((sum*si[i])%(2*(mod-1)))/2,mod))%(mod);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Best KeyBoard

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值