括号序列模型--序列dp--U86873 小Y的精灵国机房之旅

括号序列模型及解法

>Codeforces314E
给定一个长度为n的仅包含左右括号和问号的字符串,将问号变成左括号
或右括号使得该括号序列合法,求方案总数。
例如(())()()都是合法的括号序列。
◦ n<=3000

>Solution

◦括号序列问题,往往就是把左括号看成+1,右括号看成-1,我们只需要
保证任意一个前缀大于等于0,且总和为0,就代表是个合法括号序列了。
dp[i][j]表示当前到第i个字符,现在的前缀和
那么分三种情况考虑。
若第i+1个字符是左括号,则能转移到dp[i+1][j+1]
若第i+1个字符是右括号,则能转移到dp[i+1][j-1]
若第i+1个字符是问号,则能转移到dp[i+1][j-1]dp[i+1][j+1]
最终dp[n][0]就是方案总数啦。
时间复杂度为O(n^2)

 

U86873 小Y的精灵国机房之旅

题解

括号序列模型唉!

所以就可以套用上面的式子啦

把Y看做左括号,H看做右括号,C看做问号

准备AC

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int maxn=10010,mod=1e9+7;
int n;
char a[maxn];
int f[3000][3000];

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

然后发现不对劲。。。。。

 

 

 

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

那就。。。循环队列!

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

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

 

代码

#include<iostream>
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}

const int maxn=10010,mod=1e9+7;
int n;
char a[maxn];
int f[3][maxn];

int main()
{
    n=read();
    scanf("%s",a+1);
    memset(f,0,sizeof(f));
    f[0][0]=1;
    for(int i=1;i<=n;i++){
        if(a[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(a[i]=='H'){
            for(int j=0;j<i;j++){
                f[i&1][j]=f[(i-1)&1][j+1];
            }
            f[i&1][i]=0;
        }
        if(a[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];
        }
    }
    printf("%d\n",f[n&1][0]%mod);
    return 0;
}

 

posted @ 2019-11-07 17:22  晔子  阅读(330)  评论(0编辑  收藏  举报