YCH的模拟赛 T1

括号序列问题,往往就是把左括号看成+1,右括号看成-1,我们只需要保证任意一个前缀大于等于0,且总和为0,就代表是个合法括号序列了。

(f[i][j])表示当前到第(i)个字符,现在的前缀和(j)。那么分三种情况考虑。

若第(i+1)个字符是左括号,则能转移到(f[i+1][j+1])

若第(i+1)个字符是右括号,则能转移到(f[i+1][j-1])

若第(i+1)个字符是问号,则能转移到(f[i+1][j-1])(f[i+1][j+1])

最终(f[n][0])就是方案总数啦。

时间复杂度为(O(n^2))

优化:

二维数组一定会炸。。。。

那就。。。循环队列!

我们发现每次到新的一个 $i $,它只和 (i-1) 有关,所以 (i-1) 用过一次就可以销毁了,不然也是占空间

可以像这样&1​来实现循环利用

f[i & 1][0]=0

STD

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n;
int f[3005][3005];
char c[3005];

int main()
{
	scanf("%d",&n);
	scanf("%s",c+1);
	f[0][0]=1;
	for(int i=1;i<=n;i++)
	{
		if(c[i]=='Y')
		{
			for(int j=1;j<=i;j++)
			{
				f[i][j]=f[i-1][j-1];
			}
		}
		if(c[i]=='H')
		{
			for(int j=0;j<i;j++)
			{
				f[i][j]=f[i-1][j+1];
			}
		}
		if(c[i]=='C')
		{
			f[i][0]=f[i-1][1];
			for(int j=1;j<i;j++)
			{
				f[i][j]=(f[i-1][j+1]+f[i-1][j-1])%mod;
			}
			f[i][i]=f[i-1][i-1];
		}
	}
	cout<<f[n][0]%mod;
}


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
int n;
int f[3][10005];
char c[10005];

int main()
{
	freopen("data10.in","r",stdin);
	freopen("data10.out","w",stdout);
	scanf("%d",&n);
	scanf("%s",c+1);
	memset(f,0,sizeof(f));
	f[0][0]=1;
	for(int i=1;i<=n;i++)
	{
		if(c[i]=='Y')
		{
			f[i&1][0]=0;
			for(int j=1;j<=i;j++)
			{
				f[i&1][j]=f[(i-1)&1][j-1];
			}
		}
		if(c[i]=='H')
		{
			f[i&1][i]=0;
			for(int j=0;j<i;j++)
			{
				f[i&1][j]=f[(i-1)&1][j+1];
			}
		}
		if(c[i]=='C')
		{
			f[i&1][0]=f[(i-1)&1][1];
			for(int j=1;j<i;j++)
			{
				f[i&1][j]=(f[(i-1)&1][j+1]+f[(i-1)&1][j-1])%mod;
			}
			f[i&1][i]=f[(i-1)&1][i-1];
		}
	}
	cout<<f[n&1][0]%mod;
}
原文地址:https://www.cnblogs.com/lcezych/p/13266794.html