HDU 6143 Killer Names(容斥原理)

http://acm.hdu.edu.cn/showproblem.php?pid=6143

题意:

用m个字母去取名字,名字分为前后两部分,各由n个字符组成,前后两部分不能出现相同字符,问合法的组成有多少种。

思路:

$C(m,i)$表示前面用i种字母组成,那么后面的情况就是可以随便用剩下的m-i种字母,总的方法数也很简单,就是$(m-i)^{n}$。

现在问题是怎么计算用i种字母组成n长度的字符串个数?

容斥原理。$i^n-inom{i}{1}(i-1)^n+inom{i}{2}(i-2)^n-inom{i}{3}(i-3)^n+...$

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<sstream>
 6 #include<vector>
 7 #include<stack>
 8 #include<queue>
 9 #include<cmath>
10 #include<map>
11 #include<set>
12 using namespace std;
13 typedef long long ll;
14 typedef pair<int,ll> pll;
15 const int INF = 0x3f3f3f3f;
16 const int maxn=2000+5;
17 const int mod=1e9+7;
18 
19 int n, m;
20 ll c[maxn][maxn];
21 ll mul[maxn][maxn];
22 
23 void init()
24 {
25     memset(c,0,sizeof(c));
26     for(int i=0;i<=2000;i++)
27     {
28         c[i][0]=1;
29         for(int j=1;j<=i;j++)  c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
30     }
31 }
32 
33 ll qpow(ll x, ll n)
34 {
35     if(mul[x][n])  return mul[x][n];
36     ll ans=1,aa=x,bb=n;
37     while(n)
38     {
39         if(n&1)  ans=ans*x%mod;
40         x=x*x%mod;
41         n>>=1;
42     }
43     mul[aa][bb]=ans;
44     return ans;
45 }
46 
47 ll calc(ll x)
48 {
49     ll tmp=0;
50     for(int i=0;i<=x;i++)
51     {
52         if(i&1)  tmp=(tmp-c[x][i]*qpow(x-i,n)%mod+mod)%mod;
53         else tmp=(tmp+c[x][i]*qpow(x-i,n)%mod)%mod;
54     }
55     return tmp;
56 }
57 
58 int main()
59 {
60     //freopen("in.txt","r",stdin);
61     init();
62     int T;
63     scanf("%d",&T);
64     while(T--)
65     {
66         ll ans=0;
67         scanf("%d%d",&n,&m);
68         for(int i=1;i<m && i<=n ;i++)
69         {
70             ans=(ans+(c[m][i]*calc(i)%mod)*qpow(m-i,n)%mod)%mod;
71         }
72         printf("%lld
",ans);
73     }
74     return 0;
75 }
原文地址:https://www.cnblogs.com/zyb993963526/p/7387583.html