试题 算法训练 Sereja and Squares (dp+滚动数组)

在这里插入图片描述
思路:
问题转换,我们可以把小写字母看成左括号,大写字母看成右括号。总共有25种(除开x、X)。
令 f(i, j) 表示 假设括号只有一种,前 i 个数里面,填了 j 个右括号的方案数.
第i个数是问号,当前位置填左括号 f[i][j]+=f[i-1][j],当前位置填右括号f[i][j]+=f[i-1][j-1]
f[n][n/2]即为答案利用一种情况的方案数计算多种括号的方案数.
我们开文章一开始就说了,我们有25种括号,且左括号个数是 n / 2 个.
假设序列中已有 p 个左括号,那么 ?(即要填的数的个数) 里面就有 n / 2 - p 个左括号.
每一个左括号有 25 种选择,那么 ans = 25 ^ (n / 2 - q) * f(n, n / 2).

#include<bits/stdc++.h>
using namespace std;
#define ul unsigned long 
const int maxn=1e5+5;
//4294967296==2^32-1,4294967296是unsign int 的溢出值,
//对其取模就是它的自然溢出,所以不必取模
ul q[maxn];  ///下标i,表示确定了i个右括号,使用滚动数组 
char w[maxn];
int main()
{
	int n;
	scanf("%d",&n);
	scanf("%s",w+1);
	q[0]=1;
	if(n%2)   ///如果是奇数,则不满足题意 
	{
		printf("0\n");
	}
	else 
	{
		int left=0;
		for(int i=1;i<=n;i++)
	   {
	   	   if(w[i]=='?')
	   	   {
	   	   	 for(int j=i>>1;j>=1;j--)    ///j=i>>1,确定右括号的最大限 
	   	   	 {                            //若现在确定的是左括号则前面i-1个格子就是确定j个右括号的结果
                                            //若现在确定的是右括号,则前面i-1个格子确定的就是j-1个右括号的结果
	   	   	 	if(i!=n) 
	   	   	 	 q[j]+=q[j-1];
	   	   	 	 else 
	   	   	 	 q[j]=q[j-1];
	   	   	 	 //i==n一定是右括号,只要确定前n-1个格子所确定出来的n>>1-1个右括号的结果即可
			 }
		   }
		   else left++; //记录左括号个数
		    
       }
       if(left>(n>>1))
       {
       	  printf("0\n");
	   }
	   else 
	   {
	   	     ul ans=1;
	   	    for(int i=1;i<=n/2-left;i++)//还有多少个左括号没有确定左括号有25种,一种没确定答案就翻25倍
	   	    {
	   	    	ans=ans*25;
			}
			ans=ans*q[n>>1];
			printf("%u\n",ans);
	   }
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值