动规整理 CF 314e

题意:

数轴上有n个点,分为n/2对,每对的第一点用小写字母表示,第二个的用大写字母表示,且大小写字母对应。那么就能以每一对点为对角画一个正方形。保证每一对点构成的正方形不交叉。现在,有人擦掉了所有的大写字母和部分小写字母,如果让你补全有多少种方案。(字母有25种,没有'x')
n<=1e5


实际上就是有25中括号,进行配对有多少种方案。

本人水平有限,对我来说有点难。
如果只有一种括号,认为f[i][j]表示前i个字符有j个左括号没有的到配对的方案数。
如果第i个左括号,则f[i][j]=f[i-1][j-1]
如果第i个为‘?’,则f[i][j]=f[i-1][j-1]+f[i-1][j+1]
明显f[n][0]就是答案

也可以认为f[i][j]表示前i个字符有j个右括号的方案数(右括号不管有没匹配)。
如果第i个左括号,则f[i][j]=f[i-1][j]
如果第i个为‘?’,则f[i][j]=f[i-1][j-1]+f[i-1][j]
这个东西和背包的二维压缩一样,就变成了:
如果第i个左括号,则f[j]=f[j]
如果第i个为‘?’,则f[j]=f[j-1]+f[j]

上面这个明显好,毕竟解决了空间的问题。
但是25中括号怎么办呢?
每个‘?’都可以为25个中的一个。明显不能按照‘?’数量的都乘以25.左右对应的嘛!
我们发现一个括号匹配,只要左括号固定了,右括号就固定了。所以只要乘以代表左括号的‘?’的数量就好了。
所以根据上面的方法求出f[n/2]后乘以\(25^{n/2-cnt}\),其中\(cnt\)表示字符串中左括号(小写字母)的数量!


#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
char s[maxn];
int n,cnt;
unsigned f[maxn];

int main()
{
	scanf("%d",&n);
	if(n&1)
	{
		putchar('0');
		return 0;	
	}
	scanf("%s",s+1);
	f[0]=1;
	for(int i=1;i<=n;++i)
		if(s[i]>='a'&&s[i]<='z')cnt++;
		else
		{
			for(int j=i/2;j>0&&j>=i-n/2;--j)f[j]+=f[j-1];
		}
	cnt=n/2-cnt;
	unsigned ans=1;
	for(int i=1;i<=cnt;++i)ans*=25;
	cout<<ans*f[n/2]<<endl;
	return 0;
}

posted on 2022-09-15 15:07  gryzy  阅读(27)  评论(0编辑  收藏  举报

导航