逆向思维法

题目:有一个合法的字符串,合法是指左括号与右括号全部能配对,现在每次将这个序列第一个左括号删去,在将任意一个右括号删去,每次删去后的序列必须合法,求有多少种方法,答案对10000000007。

输入:

一个合法括号序列。

输出:

方案数。

样例1:

Input:

()()()()

Output:

1

样例2:

Input

(((())))()()

Output:

24

这题水过。。。。。。

首先我们很容易知道如果模拟的话很复杂,在进一步思考会发现从左到右走会有后效性,当前所选的右括号会决定序列是否合法且影响到下一次的选择,既然有后效性,那就倒过来,从右往左!可以证明到右边先选不会影响到左边。(突然想起了一道类似的题,比较复杂,我以后会写的。)附上简易的证明过程:首先明确左括号是能跟任意一个其右边的右括号匹配的,假设当前从右向左走到某一个左括号,右边的左括号已经全部满足了,左边的左括号也是能够满足,因为当前剩下的右括号全部在右边,也就是说现在任意选择一个右边的右括号与当前走到的左括号匹配都能保证剩余的右括号能与其左边的左括号匹配,即不会影响到整个序列的合法性。定义一个ans记录方案数(这里有个坑,ans初始值为1!!!),再定义一个tot记录现在右边剩余的右括号,初始值为0,遇到右括号就加1,遇到左括号就减1。思路很清晰了,代码很容易写出。

复制代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
const long long mod=10000000007ll;
char A[20000005];
long long ans=1;
int tot;
int main()
{
    
    freopen("ka.in","r",stdin);
    freopen("ka.out","w",stdout);
    scanf("%s",A);
    int len=strlen(A);
    for(int i=len-1;i>=0;i--)
    {
        if(A[i]==')')tot++;
        else if(A[i]=='('){
            ans=(ans*tot)%mod;
            tot--;
        }
    }
    printf("%I64d",ans);
    //printf("%lld",ans);
     return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_34312317/article/details/77899457