#include <bits/stdc++.h>
#define int long long
using namespace std;
typedef long long LL;
const int N = 3050, MOD = 1e9 + 7;
int n, m;
int f[N][N];
int A[N];
int mul(int a, int b, int c, int d) {
int res = 1;
res = a * b % MOD;
res = res * c % MOD;
res = res * d % MOD;
return res;
}
void slove() {
cin >> n >> m; //加法操作,乘法操作
if (n > m)
swap(n, m); //数量不影响结果
int ans = 0;
for (int i = 1; i < n; i++) {
//i表示将n个加号划分成i个集合
//A[i]表示i个加号集合的全排列数量
//同时,i个加号集合会对乘号进行划分
//会出现3种划分
ans += mul(f[n][i], A[i], f[m][i - 1], A[i - 1]); //1:用i个加号把乘号分成i-1段(加号放在两边)
ans += 2 * mul(f[n][i], A[i], f[m][i], A[i]); //2:用i个加号把乘号分成k段(有最左边是加号和最右边是加号两种情况)
ans += mul(f[n][i], A[i], f[m][i + 1], A[i + 1]); //3:i个加号把乘号分成k+1段(加号不放两段)
ans %= MOD;
}
//当i==n时,有两种情况
//1:n==m,此时只有1,2号
//否者就是n<m,此时有三种情况
if (n == m) {
// 第二种情况
ans = (ans + (2 * A[n] * A[n]) % MOD + mul(f[n][n], A[n], f[m][n - 1], A[n - 1])) % MOD;
} else {
ans += mul(f[n][n], A[n], f[m][n - 1], A[n - 1]);
ans += 2 * mul(f[n][n], A[n], f[m][n], A[n]);
ans += mul(f[n][n], A[n], f[m][n + 1], A[n + 1]);
ans %= MOD;
}
cout << ans << endl;
}
signed main() {
f[0][0] = 1;
for (int i = 1; i <= 3010; i++) {
for (int j = 1; j <= 3010; j++) {
f[i][j] = (f[i - 1][j - 1] + j * f[i - 1][j]) % MOD;
}
}
A[0] = 1;
for (int i = 1; i < 3000; i++) {
//计算阶乘
A[i] = (A[i - 1] * i) % MOD;
}
int t;
cin >> t;
while (t--) {
slove();
}
return 0;
}
2021百度之星复赛02 Add or Multiply 1 (第二类斯特林数)
おすすめ
転載: blog.csdn.net/fdxgcw/article/details/119850095
おすすめ
ランキング