百度之星2021复赛 1002-Add or Multiply 1

传送门
请添加图片描述

思路:

因为对于*和+来说,两者作用对等,于是,为了方便后续结算,当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][i1]a[i1]//乘号被划分为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);
	}
}

おすすめ

転載: blog.csdn.net/p15008340649/article/details/119855866