UVALive 6736 Army Formation (容斥原理)

  题意:给2*N的矩阵放满物品,共有M种物品,每种物品有无限个,同行列不能有相同种类的物品,问你有多少种放法。

  思路:不用容斥原理也是可以解的,用对错排的递推式做出修改,以前的错排是N对N,现在多了M-N个,这里只介绍容斥原理做法。

  容斥原理最重要的是处理好集合的关系,这个题目首先应该考虑把一行放满,有A(M,N)种,然后考虑下面的放法,要求同一列不能有一样的,我们正难则反,考虑下面有和上面一样的情况,令集合Ui表示至少有i个和上面一样,方案数是C(N,i)*A(M-i,N-i),那下面合理的办法共有U0 - U1 + U2 - U3……种,那么ans = 上 * 下

  代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<map>
#include<queue>
#include<iostream>
using namespace std;
#define LL long long
const LL Mod = 1000000007;
LL fac[1005],ni[1005];
LL qpow(LL x,int y){
    LL res = 1;
    while(y){
        if(y&1){
            res=(res*x)%Mod;
        }
        x=(x*x)%Mod;
        y>>=1;
    }
    return res;
}

void init(){
    fac[0] = 1;
    for(int i=1;i<=1002;i++){
        fac[i] = (fac[i-1]*i)%Mod;
    }
    ni[1002] = qpow(fac[1002],Mod-2);
    for(int i=1002;i>=1;i--){
        ni[i-1] = (ni[i]*i)%Mod;
    }
}

LL C(int n,int m){
    if(m<0 || m>n) return 0;
    if(m==0 || m==n) return 1;
    LL res = (fac[n]*ni[m])%Mod;
    res = (res*ni[n-m])%Mod;
    return res;
}
LL A(int n,int m){
    if(m<0 || m>n) return 0;
    LL res = (fac[n]*ni[n-m])%Mod;
    return res;
}
int main(){
    init();
    int T,n,m;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        if(n > m){
            printf("0
");
            continue;
        }
        LL up = A(m,n);
        LL down = 0;
        for(int i=0;i<=n;i++){
            LL tmp = C(n,i)*A(m-i,n-i);  tmp %= Mod;
            if(i&1) down = (down-tmp)%Mod;
            else down = (down+tmp)%Mod;
        }
        down = (down+Mod)%Mod;
        LL ans = (up*down)%Mod;
        printf("%lld
",ans);
    }
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/jifahu/p/7928339.html