http://acm.hdu.edu.cn/showproblem.php?pid=6143
题目大意:有名和姓两种字符串,每种字符串长度都是n个字符,名和姓加起来的字符种类数最多是m个,问满足条件的字符串有多少种?
解题思路:我们能够枚举左边的字符种数是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求和就可以了。
AC代码:
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 }
时间: 2024-10-15 14:36:16