http://acm.hdu.edu.cn/showproblem.php?pid=6143php
題目大意:有名和姓兩種字符串,每種字符串長度都是n個字符,名和姓加起來的字符種類數最可能是m個,問知足條件的字符串有多少種?ios
解題思路:咱們可以枚舉左邊的字符種數是x,那麼右邊就有(m-x)n種排列方式。咱們知道左邊的排列方式數量是C(m,x)*f(x)。其中f(x)=(xn-C(x,x-1)*f(x-1)-C(x,x-2)*f(x-2)……C(x,1)*f(1))。最後結果就是枚舉每個x,對C(m,x)*f(x)*(m-x)n求和就能夠了。c++
AC代碼:spa
1 #include <iostream> 2 #include <bits/stdc++.h> 3 using namespace std; 4 const long long mod=1e9+7; 5 long long a[2005][2005],num[2005]; 6 long long pow_(int n,int m) 7 { 8 long long tmp=m,ans=1; 9 while(n) 10 { 11 if(n&1) 12 { 13 ans=(ans*tmp)%mod; 14 } 15 tmp=(tmp*tmp)%mod; 16 n=n/2; 17 } 18 return ans%mod; 19 } 20 int main() 21 { 22 int t,n,m; 23 for(int i=1;i<=2002;i++) 24 { 25 a[i][0]=1,a[i][i]=1; 26 for(int j=1;j<i;j++) 27 { 28 a[i][j]=(a[i-1][j-1]+a[i-1][j]+mod)%mod; 29 } 30 } 31 while(~scanf("%d",&t)) 32 { 33 while(t--) 34 { 35 memset(num,0,sizeof(num)); 36 scanf("%d%d",&n,&m); 37 long long ans,tmp=1; 38 if(m>n) 39 { 40 ans=0,tmp=0; 41 for(int i=1;i<=n;i++) 42 { 43 tmp=0; 44 for(int j=1;j<i;j++) 45 tmp=(tmp+a[i][j]*num[j])%mod; 46 num[i]=(pow_(n,i)-tmp+mod)%mod; 47 ans=(ans+(((a[m][i]*num[i])%mod)*pow_(n,m-i))%mod+mod)%mod; 48 } 49 } 50 else 51 { 52 ans=0,tmp=0; 53 for(int i=1;i<=m-1;i++) 54 { 55 tmp=0; 56 for(int j=1;j<i;j++) 57 tmp=(tmp+a[i][j]*num[j])%mod; 58 num[i]=(pow_(n,i)-tmp+mod)%mod; 59 ans=(ans+(((a[m][i]*num[i])%mod)*pow_(n,m-i))%mod+mod)%mod; 60 } 61 } 62 printf("%lld\n",ans%mod); 63 } 64 } 65 return 0; 66 }