[Codeforces314E][DP]Sereja and Squares

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/82985269

翻译

Sereja在平面上画了n个点,第i点(1<=i<=n)坐标为(i,0)。然后Seraja在每个点上标记了一个大写或小写的英文字母。Seraja不喜欢字母’x’,所以她没有用’x’标记任何点。Seraja认为,当标记方式满足以下条件时,这些点就被“美丽地”标记了:
1.所有点能够被分成若干点对,每个点在且仅在一个点对中; 2.在每个点对中,横坐标较小的点被小写字母标记,横坐标较大的点被同一字母的大写形式标记; 3.以每组点对连线为对角线作正方形,所有作出的正方形的边没有交点且没有顶点重合;
小Petya擦去了标记在点上的一些小写或大写字母。现在Seraja想知道有几种方式标记被擦去字母的点,能够使所有点被“美丽地”标记了。

题解

诠释 暴力踩标算, N 2 N^2 过百万
实际上就是给你一些左括号,右括号全部擦去的序列
有25种括号,要求你恢复这个序列
枚举左括号的话是妥妥 N 2 N^2
换种思路
f [ i ] [ j ] f[i][j] 表示前i个字符填了j个右括号
显然j的上界是i/2
设已经找到了k个左括号
下界是k
只需要用是问号的部分更新
填左括号, f [ i ] [ j ] = f [ i 1 ] [ j ] f[i][j]=f[i-1][j]
填右括号, f [ i ] [ j ] = f [ i 1 ] [ j 1 ] f[i][j]=f[i-1][j-1]
25我们最后再乘
这样就能过了…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void pr1(int x){write(x);printf(" ");}
inline void pr2(int x){write(x);puts("");}
int n;
char ch[100005];
unsigned int f[2][50005];
int main()
{
	n=read();if(n&1)return puts("0"),0;
	scanf("%s",ch+1);
	int now=0;f[now][0]=1;int sum=0;
	for(int i=1;i<=n;i++)
	{
		if(ch[i]=='?')
		{
			now^=1;
			for(int j=0;2*j<=i;j++)f[now][j]=f[now^1][j]+f[now^1][j-1];
		}
		else sum++;
	}
	unsigned int ans=f[now][n/2];
	for(int i=1;i<=(n-2*sum)/2;i++)ans*=25;
	printf("%u\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/82985269