思路在代码中写了:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define int long long
const int maxn = 4e3 + 10;
const int mod = 1e9 + 7;
int cnt[maxn], fact[maxn], infact[maxn],inv[maxn];//求C
int dp[maxn];//dp[i]代表前i个盒子装k个球方案数和
int q_pow(int a, int b)
{
int ans = 1;
while (b)
{
if (b & 1)
{
ans = ans * a%mod;
}
b >>= 1;
a = a * a%mod;
}
return ans % mod;
}
void init()
{
fact[0] = infact[0] = 1;
for (int i = 1; i < maxn; i++)
fact[i] = fact[i - 1] * i%mod;
infact[maxn - 1] = q_pow(fact[maxn - 1], mod - 2);
for (int i = maxn - 2; i; i--)
{
infact[i] = infact[i + 1] * (i + 1) % mod;
}
}
int C(int a, int b)
{
if (a < b)
return 0;
return fact[a]*infact[b]%mod*infact[a - b] % mod;
}
void solve(){
int n, k;
cin >> n >> k;
memset(cnt, 0, sizeof cnt);
int x;
for (int i = 1; i <= n; i++){
cin >> x;
cnt[x]++;
}
for (int i = 1; i <=k; i++){
int tmp = 1;
for (int j = 1; j <= n; j++){
if (cnt[j]){
tmp = tmp * C(i - 1 + cnt[j],cnt[j])%mod;//这个组合数表示有n个相同的球,k个不同的盒子,把n个球放到盒子里,盒子允许为空
//为什么此时不是利用n个球,k个不同的盒子,不能为空呢,因为此时我们可以发现,对于一种球,可能其只能填一些地方,其他的盒子一定为空
//我们在处理完后会发现此时有一些可能是有盒子是完全为空的,所以有了接下来的删除操作
//对于该删除操作,我们可以理解为将n个球全部塞在j个盒子中的可能减去
}
}
for (int j = 1; j < i; j++)
tmp =(tmp-dp[i-j] * C(i, j))%mod;
dp[i] = tmp;
}
cout << (dp[k] % mod+mod)%mod << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int t;
init();
cin >> t;
while (t--)
solve();
}