思路:
问题转换,我们可以把小写字母看成左括号,大写字母看成右括号。总共有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);
}
}
}