CodeForces - 629C Famil Door and Brackets (dp)

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

题目大意:

给你一个长度为m的字符串,字符串中只有 左括号'('  和 右括号 ')' ,你要加入一些括号使得字符串长度变为n 并且满足合法,合法的条件是

①左括号总数等于右括号总数

②并且要求在任意一位置左括号数量>= 右括号数量 

问有多少对p,q能满足p+s+q

题解:

设dp[i][j]为前i个字符,左括号'('个数比有括号')'个数多j个的满足的pq对数

从i=0到n-m枚举p的位数,n-m-i就是q的位数,然后把两边p和q的可能情况相乘就是答案

因为p,q的每一位是‘(‘还是‘)‘不一定,两种情况都有可能,两种情况都要考虑,那么这样其实就与我们读入的s是没有关系的,我们可以提前处理出dp[i][j]的值来

这里还有一点,dp[i][j]和dp[i][-j]的值应该是一样的,因为完全可以把一个字符串的左右括号互换,互换之后就由dp[i][j]变成了dp[i][-j]

其余的详见注释叭

#include<cstring>
#include<bits/stdc++.h>
#define mod 1000000007
#define INF 1000000007
using namespace std;
typedef long long ll;
ll dp[2010][2010];
int main()
{
    //freopen("input.txt","r",stdin);
    int n,m;
    string s;
    cin>>n>>m;
    cin>>s;
    dp[0][0]=1;
    for(int i=1;i<=2000;++i)
    {
        dp[i][0]=dp[i-1][1];
        //dp[i][0]就是前i个左右括号个数相等((()))这样的
        //那么第i个一定是右括号,所以一定是由dp[i-1][1]推过来
        for(int j=1;j<=i;++j)
        {
            dp[i][j]=(dp[i-1][j-1]+dp[i-1][j+1])%mod;
            //dp[i-1][j+1]-->dp[i][j]代表第i位上是(
            //dp[i-1][j-1]-->dp[i][j]代表第i位上是)
        }
    }
    int num=0;
    int minn=INF;
    for(int i=0;i<m;++i)
    {
        if(s[i]=='(')
           num++;
        else num--;
        minn=min(minn,num);//存的是(个数大于)个数的最小数量
        //有可能是负的,这样在这一点)数量大于(数量
    }
    int len=n-m;
    ll ans=0;
    for(int i=0;i<=len;++i)//i枚举的是p len-i就是q
        for(int j=0;j<=i;++j)//j表示i左边的左括号比右括号多多少
    {
        if(j+num>len-i)continue;//右边可能存在的右括号个数不能大于
        if(minn+j<0)continue; //  保证在任意一位置  左括号数量>= 右括号数量
        ans+=(dp[i][j]*dp[len-i][j+num])%mod;
        //j是左边p左括号大于右括号的数,sum是s中左括号大于右括号的数
        //那么要满足条件p+s+q整体左括号=右括号数,则q必须是-(j+num)
        ans%=mod;
    }
    cout<<ans<<endl;


    return 0;
}

猜你喜欢

转载自blog.csdn.net/hxxjxw/article/details/82947550