"Inclusion-exclusion principle and generalized inclusion and exclusion."

<> Yes

<First update>


<Text>

Inclusion-exclusion principle

Basic concepts

We assume Collection \ (S \) , and \ (n-\) sets \ (A_1, A_2, ..., A_n \) , each set \ (A_i \) in an element having properties \ (P_i \) set size, and now we do not have any required properties, i.e. number of elements, having the following calculation formula:
\ [\ left | \ bigcap_. 1} ^ {n-I = \ overline A_i {} \ right | = | S | + \ sum_ {T \ subseteq \ {1,2, ..., n \}, T \ not = \ emptyset} (- 1) ^ {| T |} \ left | \ bigcap_ {i \ in T} a_i \ right | \]

Of course, we also have another form:

\[\left | \bigcup_{i=1}^nA_i \right |=\sum_{T\subseteq \{1,2,...,n\}}(-1)^{|T|-1}\left | \bigcap_{i\in T} A_i \right |\]

Both forms can be obtained easily interchangeable, essentially the same.

How to understand the significance of their combination, we can explain:

Form \ (1 \) : the number of elements does not have any character \ (= \) is the total number of elements \ (- \) comprising at least a number of elements of nature and \ (+ \) comprising at least two properties and the number of elements known \ (- \) the number of elements having at least three properties and \ (... \)

Form \ (2 \) : All size and diversity set \ (= \) all the set and the size of the \ - (\) intersection between the size of each of the two sets \ (+ \) between each set of three intersection size \ (... \)

Cancer elections

Description

Assembly elections cancer began. Election of the organizers of Magolor do not want people to be elected not cancer, because cancer is not cancer who elected leaders to make the election lasts, people famous, it is every cancer do not want to see.

Therefore, Magolor want you (whether you are not cancer) to help him figure out how much probability it will not happen. Election of cancer have \ (n \) bit voters and \ (k \) candidates. Because voters are also cancer, so voters would vote random (but fortunately not abstain or cast votes). Cancer is a candidate if and only if there is at least a voter to vote for him.

Now, Magolor want to know all the voting scheme, how many kinds of programs are met: All candidates are the cancer. Since particularly large number of programs, Magolor you only need to output the answer \ (\ bmod \ 998244363 \) the remainder can be.

Input Format

第一行输入\(T\)表示有组\(T\)数据。

接下来行\(T\)每行两个整数: \(n,k\)

Output Format

输出文件\(T\)行每行一个整数表示答案。

Sample Input

1
4 3

Sample Output

36

解析

我们可以把每一种投票方案看做一种元素,具备一个性质的元素就是有一个候选人没选的方案。那么我们就可以套用容斥原理的第一个模型:没有任何人落选的方案数就是全部方案数 \(-\) 至少有一个人落选的方案数之和 \(+\) 至少有两个人落选的方案数之和 \(...\)

那么我们的问题就是快速计算至少有\(m\)个人落选的方案数之和,显然,方案数即为:

\[\binom{k}{m}(k-m)^n\]

那么根据容斥原理,答案即为:

\[k^n+\sum_{i=1}^m(-1)^i\binom{k}{i}(k-i)^n\]

注意,模数是\(998244363=3\times 19\times 97\times 180547\),需要先根据每一个模数算一个答案,然后用中国剩余定理合并答案。组合数需要用\(Lucas\)定理计算,时间复杂度\(O(k\times(\log_2 n+\log_{mod}k))\)

从另一个角度考虑,\(ans=k!\times S(n,k)\),所以对于\(k\geq 180547\),答案为\(0\),直接输出即可。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 190000 , p[] = {0,3,19,97,180547};
int inv[5][N],fac[5][N],ans[5],n,m;
inline int add(int a,int b,int Mod) { return a + b >= Mod ? a + b - Mod : a + b; }
inline int mul(int a,int b,int Mod) { return 1LL * a * b % Mod; };
inline int sub(int a,int b,int Mod) { return a - b < 0 ? a - b + Mod : a - b; }
inline void Add(int &a,int b,int Mod) { a = add( a , b , Mod ); }
inline void Mul(int &a,int b,int Mod) { a = mul( a , b , Mod ); }
inline void Sub(int &a,int b,int Mod) { a = sub( a , b , Mod ); }
inline int quickpow(int a,int b,int Mod)
{
    int res = 1;
    for ( ; b ; Mul(a,a,Mod) , b>>=1 )
        if ( 1 & b ) Mul(res,a,Mod);
    return res;
}
inline void init(void)
{
    for (int k=1;k<=4;k++)
    {
        fac[k][0] = inv[k][0] = 1;
        for (int i=1;i<p[k];i++)
            fac[k][i] = mul( fac[k][i-1] , i , p[k] );
        inv[k][p[k]-1] = quickpow( fac[k][p[k]-1] , p[k]-2 , p[k] );
        for (int i=p[k]-2;i>=1;i--)
            inv[k][i] = mul( inv[k][i+1] , i+1 , p[k] );
    }
}
inline int C(int n,int m,int k)
{
    if ( n < m || n < 0 || m < 0 ) return 0;
    int res = fac[k][n];
    return mul( res , mul( inv[k][m] , inv[k][n-m] , p[k] ) , p[k] );
}
inline int Lucas(int n,int m,int k)
{
    if ( m == 0 ) return 1;
    int res = Lucas( n/p[k] , m/p[k] , k );
    return mul( res , C( n%p[k] , m%p[k] , k ) , p[k] );
}
inline int Exeuclid(int a,int b,int &x,int &y)
{
    if ( b == 0 ) return x = 1 , y = 0 , a;
    int t = Exeuclid( b , a%b , x , y );
    int _x = x , _y = y;
    x = _y , y = _x - a / b * _y;
    return t;
}
inline int ExCRT(void)
{
    int M = p[1] , res = ans[1] % M , t , k , x , y;
    for (int i=2;i<=4;i++)
    {
        k = ( (ans[i]-res) % p[i] + p[i] ) % p[i];
        t = Exeuclid( M , p[i] , x , y );
        x = x * (k/t) % (p[i]/t);
        res = res + x * M;
        M = M * p[i] / t;
        res = ( res % M + M ) % M;
    }
    return res;
}
inline int solve(void)
{
    for (int k=1;k<=4;k++)
    {
        ans[k] = quickpow( m , n , p[k] );
        for (int i=1;i<=m;i++)
        {
            int val = mul( Lucas(m,i,k) , quickpow(m-i,n,p[k]) , p[k] );
            if ( i & 1 ) Sub( ans[k] , val , p[k] );
            else Add( ans[k] , val , p[k] );
        }
    }
}
int main(void)
{
    init();
    int T; long long N,M;
    scanf("%d",&T);
    while ( T --> 0 )
    {
        scanf("%lld%lld",&N,&M);
        if ( M >= 180547 ) puts("0");
        else n = N , m = M , solve(),
             printf("%d\n",ExCRT());
    }
    return 0;
}

小w的喜糖

Description

废话不多说,反正小w要发喜糖啦!!

小w一共买了n块喜糖,发给了n个人,每个喜糖有一个种类。这时,小w突发奇想,如果这n个人相互交换手中的糖,那会有多少种方案使得每个人手中的糖的种类都与原来不同。

两个方案不同当且仅当,存在一个人,他手中的糖的种类在两个方案中不一样。

Input Format

第一行,一个整数n

接下来n行,每行一个整数,第i个整数Ai表示开始时第i个人手中的糖的种类

对于所有数据,1≤Ai≤k,k<=N,N<=2000

Output Format

一行,一个整数Ans,表示方案数模1000000009

Sample Input

6  
1  
1  
2  
2  
3  
3

Sample Output

10

解析

首先我们认为同种糖的每一个也都是不同的,方便计数。

我们把一个方案看做一个元素,有一个人拿着原来和自己种类相同的糖看做满足一个性质,然后套用容斥原理\(...\)

那么我们就要计算所有人中至少有\(i\)个人拿着和自己同种糖的方案数,可以考虑\(dp\)计数。

\(f[i][j]\)代表前\(i\)种糖,有\(j\)个人拿着自己同种糖的方案数,可以直接转移:

\[f[i][j]=\sum_{k=0}^{min(j,cnt[i])}f[i-1][j-k]\times\binom{cnt[i]}{k}\times cnt[i]^{\underline{k}}\]

组合意义:前\(i-1\)种糖中已经有\(j-k\)个人拿着自己同种的糖了,现在第\(i\)种糖这样的人要有\(k\)个,方案就是\(cnt[i]\)个人中选\(k\)个人,第一个人有\(cnt[i]\)种选择选到同种糖,第二个人有\(cnt[i]-1\)种可能选到同种糖\(...\)

\(m\)为颜色总数,然后容斥:
\[ans=\sum_{i=0}^m(-1)^i\times f[m][i]\times (n-i)!\]

由于我们一开始把同种糖的每一个都看作本质不同的,所以最后要除掉每一种颜色出现次数的阶乘。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 2020 , Mod = 1e9+9;
int n,m,a[N],cnt[N],f[N][N],fac[N],inv[N],ans;
inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
inline int mul(int a,int b) { return 1LL * a * b % Mod; };
inline int sub(int a,int b) { return a - b < 0 ? a - b + Mod : a - b; }
inline void Add(int &a,int b) { a = add( a , b ); }
inline void Mul(int &a,int b) { a = mul( a , b ); }
inline void Sub(int &a,int b) { a = sub( a , b ); }
inline int quickpow(int a,int b) { int res = 1; for (;b;Mul(a,a),b>>=1) if ( 1 & b ) Mul(res,a); return res; }
inline void input(void)
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        cnt[a[i]]++;
    }
}
inline void init(void)
{
    fac[0] = inv[0] = 1;
    for (int i=1;i<=n;i++)
        fac[i] = mul( fac[i-1] , i );
    inv[n] = quickpow( fac[n] , Mod-2 );
    for (int i=n-1;i>=1;i--)
        inv[i] = mul( inv[i+1] , i+1 );
    sort( cnt+1 , cnt+n+1 );
    reverse( cnt+1 , cnt+n+1 );
    for (int i=1;i<=n+1;i++)
        if ( cnt[i] == 0 ) { m = i-1 ; break; }
}
inline int C(int n,int m) { return mul( fac[n] , mul( inv[m] , inv[n-m] ) ); }
inline int A(int n,int m) { return mul( fac[n] , inv[n-m] ); }
inline void DynamicProgram(void)
{
    f[0][0] = 1;
    for (int i=1,lim=cnt[1];i<=m;lim+=cnt[++i])
        for (int j=0;j<=lim;j++)
            for (int k=0;k<=min(cnt[i],j);k++)
                Add( f[i][j] , mul( f[i-1][j-k] , mul( C(cnt[i],k) , A(cnt[i],k) ) ) );
}
inline void solve(void)
{
    for (int i=0;i<=n;i++)
        if ( i & 1 ) Sub( ans , mul( f[m][i] , fac[n-i] ) );
        else Add( ans , mul( f[m][i] , fac[n-i] ) );
    for (int i=1;i<=m;i++)
        Mul( ans , inv[cnt[i]] );
}
int main(void)
{
    input();
    init();
    DynamicProgram();
    solve();
    printf("%d\n",ans);
    return 0;
}

广义容斥原理

基础概念

用语言描述,容斥原理求的是不满足任何性质的方案数,我们通过计算所有至少满足\(k\)个性质的方案数之和来计算。

同样的,我们可以通过计算所有至少满足\(k\)个性质的方案数之和来计算恰好满足\(k\)个性质的方案数。这样的容斥方法我们称之为广义容斥原理。

容斥方法

首先,我们设\(\alpha(k)\)代表所有至少满足\(k\)的性质的方案数之和。

也就是说:

\[\alpha(0)=|S|\\ \ \\ \alpha(1)=\sum_{i}|A_i|\\ \ \\ \alpha(2)=\sum_{i,j}|A_i\cap A_j| \\ ...\\ \ \\ \alpha(k)=\sum_{T\subseteq\{1,2,...,n\},|T|=k}\left | \bigcap_{i\in T}A_i \right |\]

我们发现\(\alpha(k)\)将具有\(p(p\geq k)\)个性质的元素计算了\(\binom{k}{p}\)次。

假设\(\beta(k)\)代表恰好具有\(k\)个元素的方案数,则有递推公式如下:

\[\beta(k)=\alpha(k)-\sum_{i=k+1}^n\binom{i}{k}\beta(i)\]


<后记>

Guess you like

Origin www.cnblogs.com/Parsnip/p/11530658.html