思路:
因为对于*和+来说,两者作用对等,于是,为了方便后续结算,当n大于m的时候,使其值交换。
考虑对+进行划分,可以划分为(1,2,3…n)个集合,对于每一种划分,我们可以将乘号以“填空”的方式填入每个集合的左边或者右边,需要注意的是,两个相邻的集合之间一定要有一个乘号,否则这两个集合就可以合并为一个集合,用这种方式,加号可以将乘号划分为最多n-1,n,n+1个集合,至此,还没完,对于加号的每个集合来说,集合内部的元素的顺序不会影响最终的结果,但集合与集合的顺序会,因而,我们还需要知道每种划分的集合数的全排列个数。
我们设将加号划分为了i个集合,f[x][y]为将x个元素划分为y个集合的种类数,a[x]为x个不同元素的全排列数,将那么对于该种划分,它的本质不同的个数为:
a n s + = f [ n ] [ i ] ∗ a [ i ] ∗ f [ m ] [ i − 1 ] ∗ a [ i − 1 ] ans+=f[n][i]*a[i]*f[m][i-1]*a[i-1] ans+=f[n][i]∗a[i]∗f[m][i−1]∗a[i−1]//乘号被划分为n-1个集合
a n s + = f [ n ] [ i ] ∗ a [ i ] ∗ f [ m ] [ i ] ∗ a [ i ] ∗ 2 + ans+=f[n][i]*a[i]*f[m][i]*a[i]*2+ ans+=f[n][i]∗a[i]∗f[m][i]∗a[i]∗2+//乘号被划分为n个集合,*2的原因是每个加号集合的左右两边都可以填入乘号集合
a n s + = f [ n ] [ i ] ∗ a [ i ] ∗ f [ m ] [ i + 1 ] ∗ a [ i + 1 ] ans+=f[n][i]*a[i]*f[m][i+1]*a[i+1] ans+=f[n][i]∗a[i]∗f[m][i+1]∗a[i+1]//乘号被划分为n+1个集合
求n个元素的m个划分参考第二类斯特林数即可:
f[1][1] = 1;
for(int i = 2; i <= 3001; i++)
{
for(int j = 1; j <= i; j++)
{
f[i][j] = f[i-1][j-1] + j*f[i-1][j]%mod;
f[i][j]%=mod;
}
}
以下为ac代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<map>
#include<queue>
#include<math.h>
#include<vector>
using namespace std;
#define ll long long
const ll mod = 1e9+7;
ll f[3010][3010];
ll a[3010];
void get()
{
f[1][1] = 1;
for(int i = 2; i <= 3001; i++)
{
for(int j = 1; j <= i; j++)
{
f[i][j] = f[i-1][j-1] + j*f[i-1][j]%mod;
f[i][j]%=mod;
}
}
}
int main()
{
int t;
cin>>t;
f[1][1] = 1;
get();
a[1] = 1;
for(int i = 2; i <= 3001; i++)
a[i] = a[i-1]*i%mod;
while(t--)
{
ll n,m;
scanf("%lld%lld",&n,&m);
if(n > m)swap(n,m);
ll ans = 0;
for(int i = 1; i < n; i++)
{
ans += f[n][i]*a[i]%mod*f[m][i-1]%mod*a[i-1]%mod;
ans%=mod;
ans += f[n][i]*a[i]%mod*f[m][i]%mod*a[i]%mod*2;
ans%=mod;
ans += f[n][i]*a[i]%mod*f[m][i+1]%mod*a[i+1]%mod;
}
ans%=mod;
if(n == m)
{
ans = ans + (2*a[n]*a[n])%mod + f[n][n]%mod*a[n]%mod*f[m][n-1]%mod*a[n-1]%mod;
printf("%lld\n",ans%mod);
continue;
}
else
{
ans += f[n][n]*a[n]%mod*f[m][n-1]%mod*a[n-1]%mod;
ans%=mod;
ans += f[n][n]*a[n]%mod*f[m][n]%mod*a[n]%mod*2%mod;
ans%=mod;
ans += f[n][n]*a[n]%mod*f[m][n+1]%mod*a[n+1]%mod;
}
printf("%lld\n",ans%mod);
}
}