SDUT 2022 Winter Individual Contest - A(D)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDUT 2022 Winter Individual Contest - A(D)相关的知识,希望对你有一定的参考价值。

D - Brackets

链接: link

题意:

给定一个括号序列,现在允许最多反转一段区间,使得 ( ( (变成 ) ) ) ) ) )变成 ( ( (,问这段括号序列在最多可反转一次情况下,能否是合法括号序列

思路:

两重循环枚举需要反转的区间,然后判断反转后,当前这种序列是否合法,针对判断序列合法,有两种判断方法,一种是记忆化搜索,另一种就是区间和+最大最小值判断法
两种方法都需要预处理, ( ( (视为 1 1 1 ) ) )视为 − 1 -1 1
记忆化搜索的话,定义 f ( p o s , s u m , s t a t e ) f(pos,sum,state) f(pos,sum,state)为判断位置到了 p o s pos pos, 1 − p o s − 1 1-pos-1 1pos1的总和,state为反转的三种状态
0 0 0代表直到当前位置为止,一个都没括号都没反转
1 1 1代表当前这个位置反转了
2 2 2代表前面出现过反转了,后面不会再出现反转
这就相当于枚举反转区间
001122 001122 001122,这样的序列就代表 [ 1 , 2 ] [1,2] [1,2]没反转, [ 3 , 4 ] [3,4] [3,4]反转, [ 5 , 6 ] [5,6] [5,6]没反转
这样的话,当遍历完整个序列时,判断序列是否合法,只需要看区间的总和是否为 1 1 1,且区间最小值是否 ≥ 0 ≥0 0(在遍历过程中,通过总和是否 < 0 <0 <0来判断,效果一样)

#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 5555;
char s[N];
int a[N];
int len;
int dp[N][N][3];
int vis[N][N][3];
bool f(int pos, int sum, int state) 
    if (sum < 0) return 0;
    if (state > 2) return 0;
    if (pos == len + 1) 
        if (sum == 0) return 1;
        return 0;
    
    if (vis[pos][sum][state]) return dp[pos][sum][state];

    bool now = f(pos, sum, state + 1);
    if (state == 0)
        now |= f(pos + 1, sum + a[pos], state);
    else if (state == 1)
        now |= f(pos + 1, sum - a[pos], state);
    else
        now |= f(pos + 1, sum + a[pos], state);
    vis[pos][sum][state] = 1;

    return dp[pos][sum][state] = now;

int main() 
    cin >> s + 1;
    len = strlen(s + 1);
    for (int i = 1; i <= len; i++) 
        if (s[i] == '(')
            a[i] = 1;
        else
            a[i] = -1;
    
    if (f(1, 0, 0))
        puts("possible");
    else
        puts("impossible");


第二种方法区间和+最大最小值
先预处理出来区间和,区间最大最小值
然后再枚举反转的区间
假设枚举的区间为 [ l , r ] [l,r] [l,r]
那么当前区间想要合法的条件是
s u m ( 1 , l − 1 ) − s u m ( l , r ) + s u m ( r , n ) = 0 sum(1,l-1)-sum(l,r)+sum(r,n)=0 sum(1,l1)sum(l,r)+sum(r,n)=0首先要保证整段区间的左括号右括号相同,因为是反转,所以带负号
m i n ( 1 , l − 1 ) ≥ 0 min(1,l-1)≥0 min(1,l1)0 a n d and and s u m ( 1 , l − 1 ) − m a x ( l , r ) > = 0 sum(1,l-1)-max(l,r)>=0 sum(1,l1)max(l,r)>=0 a n d and and s u m ( 1 , l − 1 ) − s u m ( l , r ) + m i n ( r + 1 , n ) > = 0 sum(1,l-1)-sum(l,r)+min(r+1,n)>=0 sum(1,l1)sum(l,r)+min(r+1,n)>=0
m i n v ( 1 , l − 1 ) < 0 minv(1,l-1)<0 minv(1,l1)<0就说明出现了右括号过多的情况,或者左括号还没出现,右括号就出现了,无法匹配的情况,此时无论怎么反转右边的区间都不能合法
s u m ( 1 , l − 1 ) − m a x ( l , r ) < 0 sum(1,l-1)-max(l,r)<0 sum(1,l1)max(l,r)<0,说明在反转后, [ l , r ] [l,r] [l,r]过多的左括号无法与弥补左区间的右括号,所以说明反转后 [ 1 , r ] [1,r] [1,r]这段区间右括号剩下了,无法匹配的情况
s u m ( 1 , l − 1 ) − s u m ( l , r ) + m i n ( r + 1 , n ) < 0 sum(1,l-1)-sum(l,r)+min(r+1,n)<0 sum(1,l1)sum(l,r)+min(r+1,n)<0,说明在反转后 [ 1 , n ] [1,n] [1,n]这段区间出现了,右括号剩下,无法匹配的现象
只要都满足,说明这段区间在修改后,是合法的

#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
const int N = 5555;
char s[N];
int sum[N][N];
int maxv[N][N], minv[N][N];

int main() 
    cin >> s + 1;
    int len = strlen(s + 1);
    for (int i = 1; i <= len; i++) 
        int all = 0;
        int Max = 0, Min = 0;
        for (int j = i; j <= len; j++) 
            if (s[j] == '(')
                all++;
            else
                all--;
            sum[i][j] = all;
            Max = max(Max, all);
            Min = min(Min, all);
            maxv[i][j] = Max;
            minv[i][j] = Min;
        
    

    if (sum[1][len] == 0 && minv[1][len] == 0) 
        puts("possible");
        return 0;
     else 
        bool flag = 0;
        for (int i = 1; i <= len; i++) 
            for (int j = i; j <= len; j++) 
                if (sum[1][i - 1] - sum[i][j] + sum[j + 1][len] != 0) 
                    continue;
                
                if (minv[1][i - 1] < 0 || sum[1][i - 1] - maxv[i][j] < 0 ||
                    sum[1][i - 1] - sum[i][j] + minv[j + 1][len] < 0)
                    continue;
                flag = 1;
                break;
            
            if (flag) break;
        
        if (flag)
            puts("possible");
        else
            puts("impossible");
    

To be continued
如果你有任何建议或者批评和补充,请留言指出,不胜感激

以上是关于SDUT 2022 Winter Individual Contest - A(D)的主要内容,如果未能解决你的问题,请参考以下文章

SDUT 2022 Winter Team Contest - 1

SDUT 2022 Winter Individual Contest - A(D)

SDUT 2022 Winter Individual Contest - D(K)

SDUT 2022 Winter Individual Contest - D(K)

SDUT 2022 Winter Individual Contest - D(K)

SDUT 2022 Winter Individual Contest - A(D)