hdu 6143 组合数学+dp

来源:互联网 发布:c语言中结构体的使用 编辑:程序博客网 时间:2024/06/15 02:09

题意: m个字母,组成两个长度为n的字符,其中一个字母不能同时出现在两个串中。问总方案?


思路:枚举m个中恰好有i个在第一个串,有j个在第二个串。。然后求个和。。具体其中n个空恰好k种颜色,可以用dp预处理。

dp[j][i]=((dp[j-1][i]*i)%mod+(dp[j-1][i-1]*i)%mod)%mod;


代码:

#include<bits/stdc++.h>using namespace std;#define MEM(a,b) memset(a,b,sizeof(a))#define bug puts("bug");#define PB push_back#define MP make_pair#define X first#define Y secondtypedef unsigned long long ll;typedef pair<int,int> pii;const int maxn=4e5+10;const int mod=1e9+7;using namespace std;int t,m,n,k;ll C[2005][2005];ll dp[2005][2005];ll A(ll x){    ll ret=1;    for(int i=1;i<=x;i++)        ret=(ret*i)%mod;    return ret;}int main(){    C[1][0] = C[1][1] = 1;    for (int i = 2; i < 2005; i++){        C[i][0] = 1;        for (int j = 1; j < 2005; j++)            C[i][j] = (C[i - 1][j] + C[i - 1][j - 1])%mod;    }    for (ll i = 1; i < 2005; i++){        dp[i][i]=A(i);        for (ll j = i+1; j < 2005; j++)            dp[j][i]=((dp[j-1][i]*i)%mod+(dp[j-1][i-1]*i)%mod)%mod;    }    scanf("%d",&t);    while(t--){        scanf("%d%d",&n,&m);        ll ans=0;        for(int i=1;i<m;i++)            for(int j=m-i;j>0;j--){                ans=(ans+((C[m][i]*dp[n][i])%mod)*((C[m-i][j]*dp[n][j])%mod))%mod;            }        printf("%lld\n",ans);    }    return 0;}