题意:每个人的名字由两部分组成,每部分的长度是n,给你m种字符,最多能构成多少个人的名字。
分析:就是一个组合数。如果n个长度用x个字符表达,那就相当于n个不同小球放在x个不同的盒子里。设其结果为f(x),那么f(x) = x ^ n - C(x, 1) * f(x - 1) - C(x, 2) * f(x - 2) …… - C(x, x - 1) * f(1).
然后就枚举两边各用了多少种字符统计结果。
#include<cstdio>
#define mo 1000000007
#include<iostream>
using namespace std;
typedef long long ll;
ll n, m;
ll C[2005][2005];
ll mul[10000];
ll cal[2005];
ll quickM(ll a, ll b){
ll ans = 1;
while(b){
if(b & 1) ans = ans * a % mo;
b >>= 1;
a = a * a % mo;
}
return ans;
}
int main(){
mul[0] = 1;
for(ll i = 1; i <= 3000; i++) mul[i] = mul[i] * (i - 1) % mo;
C[0][0] = 1;
for(int i = 1; i <= 2001; i++){
C[i][0] = 1;
for(int j = 1; j <= i; j++){
C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % mo;
}
}
int T;
scanf("%d", &T);
while(T--){
scanf("%lld%lld", &n, &m);
ll ans = 0;
for(ll i = 1; i <= n; i++){
cal[i] = quickM(i, n);
for(int j = 1; j < i; j++){
cal[i] -= C[i][j] * cal[j] % mo;
cal[i] = (cal[i] + mo ) % mo;
}
}
for(ll i = 1; i <= n; i++){
if(i >= m) break;
for(ll j = 1; j <= n; j++){
if(j > m - i) break;
ans += C[m][i] * cal[i] % mo * cal[j] % mo * C[m - i][j] % mo;
ans %= mo;
}
}
printf("%lld\n", ans);
}
return 0;
}