• Codeforces Round #594 (Div. 2) D1. The World Is Just a Programming Task (Easy Version)


    传送门

    题意
    可以选择一对位置进行交换,找出括号序列的操作后合法的的最大 位置个数,
    合法即为没有失配的括号比如“)()(”、")())(("等
    操作就是,当前位置时 p,把p+1~n放在位置1的前面;若操作后序列合法,那么该序列对应的满足条件的位置个数+1;

    思路
    左括号数 != 右括号数,那么答案为0;
    左括号数 == 右括号数,
    可以把等式改为:
    已匹配的左括号数 == 已匹配的右括号数 && 失配的左括号数 == 失配的右括号数。 例如: “)()()(”, 失配的左括号有1个。

    我们的操作是把后面的移到前面来,即前面的也变成后面的 (说的比较模糊 ) ,那么
    我们定义 ‘( ’ 权值为 1,‘ )’ 权值为 -1
    求出括号转化为权值后的前缀和,找到最小的非正前缀和s 。【最多的失配’)’】
    设最小非正前缀和s 的位置为p ,那么 p+1~n一定不存在失配的右括号,否则就存在前缀和比s 更小,不符合题意。

    要使操作后序列合法,那么肯定要让失配的右括号转为匹配,即需要同样数目的失配的左括号移到前面来。即枚举 p+1~n的断点k,k到n的后缀 s’ 等于 -s 时,移动后满足要求。

    断点肯定不在1~p中,因为操作后的新序列的左部分仍然有失配的右括号。

    也不可能存在,操作后的新序列后缀上多了失配的左括号【…()()()(】,因为这样,在操作前的原序列最大后缀 s’ 就大于 s,而失配的左括号数是等于失配的右括号数的,所以明显矛盾。

    AC代码

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int N=5e2+5;
    const int inf=0x3f3f3f3f;
    const int mod=1e9+7;
    #define ls (i<<1)
    #define rs (i<<1|1)
    #define fi first
    #define se second
    #define mk make_pair
    #define mem(a,b) memset(a,b,sizeof(a))
    LL read()
    {
        LL x=0,t=1;
        char ch;
        while(!isdigit(ch=getchar())) if(ch=='-') t=-1;
        while(isdigit(ch)){ x=10*x+ch-'0'; ch=getchar(); }
        return x*t;
    }
    int n;
    char str[N];
    int flag,sum[N];
    inline int cal(int p1,int p2)
    {
        swap(str[p1],str[p2]);
        int res=0,minn=0,pos=0,cnt=0;
        for(int i=1;i<=n;i++)
        {
             cnt+= str[i]=='('?1:-1;
             if(minn>cnt)
             {
                 minn=cnt;
                 pos=i;
             }
        }
        cnt=0;
        for(int i=n;i>pos;i--)
        {
            cnt+= str[i]=='('?1:-1;
            if(minn+cnt==0) res++;
        }
        swap(str[p1],str[p2]);
        return res;
    }
    int main()
    {
        n=read();
        int ans=0,ansl,ansr;
        scanf("%s",str+1);
        int cnt0=0,cnt1=0;
        for(int i=1;i<=n;i++)
            if(str[i]=='(') cnt1++;
            else cnt0++;
        if(cnt0!=cnt1)
        {
            printf("0
    1 1
    ");
            return 0;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=i;j<=n;j++)
            {
                int t=cal(i,j);
                if(t>ans)
                {
                    ans=t;
                    ansl=i;
                    ansr=j;
                }
            }
        }
        printf("%d
    %d %d
    ",ans,ansl,ansr);
        return 0;
    }
    
  • 相关阅读:
    【Linux 日常】设置动态链接库目录
    某站视频python抓取: m3u8转mp4
    GDB 主要调试命令
    算法【查找一】
    算法【排序四】
    算法【排序三】
    Vim常用命令整理
    【OpenCV】贝叶斯之肤色分割模型
    算法【排序二】
    算法【排序一】
  • 原文地址:https://www.cnblogs.com/DeepJay/p/12025182.html
Copyright © 2020-2023  润新知