1. 程式人生 > >UVa 11481 Arrange the Numbers (組合數學+容斥原理)

UVa 11481 Arrange the Numbers (組合數學+容斥原理)

UVa 11481 Arrange the Numbers

題目大意:

可以將序列1,2,3,...n任意重排,但重排後的前m(mn)個位置恰好有k(km)個不變,求方案數除以1000000007的餘數.
(注意是前m個位置恰好有k個不變,也就是說前m個位置的另外m-k個必須改變)

題目分析:

首先,前m個位置恰好有k個不變,則有Ckm個方案數,那麼總共的方案數為CkmAnknk.

但是,方案數中還存在前m個元素中另外m-k個元素仍在原位置的情況.

利用容斥原理:
減去1個元素在原位置的方案數,加上2個元素在原位置的方案數…

所以總方案數為Ckm(Anknknk

i=1(1)iCimkAnkinki).

程式碼:

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

const int maxn=1000;
const int MOD=1000000007;

int C[maxn+1][maxn+1],A[maxn+1];//C[i][j]表示i個元素選j個元素的種類數,A[i]表示i個元素選i個元素的排列種類數 

void init(int n)
{
    C[0][0]=1;
    for(int i=1;i<=n;i++) {
        C[i][0
]=1; for(int j=1;j<=n;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%MOD; } A[0]=1; for(int i=1;i<=n;i++) A[i]=(1ll*A[i-1]*i)%MOD; } int main() { init(maxn); int T,N,M,K,kase=0; scanf("%d",&T); while(T--) { scanf("%d%d%d",&N,&M,&K); int B=A[N-K]; for
(int i=1;i<=N-K;i++) B=(0ll+B+((i&1)?-1:1)*(1ll*C[M-K][i]*A[N-K-i]%MOD))%MOD; B=(B%MOD+MOD)%MOD;//注意加法和乘法的溢位 printf("Case %d: %lld\n",++kase,1ll*C[M][K]*B%MOD); } return 0; }