Card Game

D06發表於2024-10-16
  • 沉睡的記憶輕輕將你喚醒。記得三年前的五一,正是關於卡特蘭數的折線法證明,同時相容著【數形結合】和【正難則反】的思想,重新整理了你對OI的認知
  • 將卡牌的匹配關係視為括號序列,也與【字首和非負】的感受相關。而合法的括號序列數又可以用卡特蘭數來刻畫。\(Cat_{n}=\frac{C^{n}_{2n}}{n+1}=C^{n}_{2n}-C^{n+1}_{2n}\),後者是到(n-1,n+1)的方案數,與非法方案構成雙射;由於其關於二叉樹的中序遍歷,因此也可以用\({\textstyle \sum_{i=1}^{n}}H_{i-1}H_{n-i}\)的遞推公式求解
  • 得到了這一關鍵提示後,也是成功獨立做出這道題啦~
  • 【除錯程式】滾動陣列的清空
點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
long long f[2][505][505],g[505][505],h[2][505][505];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int n,m;
	cin>>n>>m;
	f[0][0][0]=1;
	for(int i=1;i<=m;i++)
	{
		memset(f[i&1],0,sizeof(f[i&1]));
		for(int j=0;j<=i;j++)
		{
			for(int k=0;j+k<=i;k++)
			{
				if(k==0)
				{
					if(j)
					{
						f[i&1][j][k]=f[i&1^1][j-1][k];
					}
				}
				f[i&1][j][k]+=f[i&1^1][j][k+1];
				//add ')'
				if(k)
				{
					f[i&1][j][k]+=f[i&1^1][j][k-1];
				}//add '('
				f[i&1][j][k]%=mod;
			}
		}
	}
	/*
	for(int j=0;j<=m;j++)
	{
		cout<<j<<':'<<f[m][j][0]<<endl;
	}
	*/
	h[0][0][0]=1;
	for(int i=1;i<=m;i++)
	{
		memset(h[i&1],0,sizeof(h[i&1]));
		for(int j=0;j<=i;j++)
		{
			for(int k=0;j+k<=i;k++)
			{
				if(j)
				{
					h[i&1][j][k]=h[i&1^1][j-1][k];
				}//add'('
				if(j==0)
				{
					if(k)
					{
						h[i&1][j][k]+=h[i&1^1][j][k-1];
					}
				}
				h[i&1][j][k]+=h[i&1^1][j+1][k];
				h[i&1][j][k]%=mod;
				//add')'
			}
		}
	}
	/*
	for(int j=0;j<=m;j++)
	{
		cout<<j<<':'<<h[m][j][0]<<endl;
	}
	*/
	g[1][0]=1;
	for(int j=2;j<=n;j++)
	{
		for(int k=0;k<=m;k++)
		{
			for(int l=0;l<=k;l++)
			{
				g[j][k]+=(g[j-1][k-l]*h[m&1][l][0]%mod);
			}
			g[j][k]%=mod;
		}
	}
	long long ans=0;
	for(int i=0;i<=m;i+=2)
	{
		ans=ans+g[n][i]*f[m&1][i][0]%mod;
	}
	cout<<ans%mod<<endl;
	return 0;
}

相關文章