2021百度之星复赛02 Add or Multiply 1 (第二类斯特林数)

请添加图片描述

#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;
}


おすすめ

転載: blog.csdn.net/fdxgcw/article/details/119850095