zoukankan      html  css  js  c++  java
  • 529A And Yet Another Bracket Sequence

    传送门

    题目大意

    给定有一个长度为n

    n的括号序列,现在有两种操作:

    1. 在任意一个位置插入有一个左括号或右括号
    2. 将末尾的一个括号放到最前面

    可以对这个序列进行若干次操作,问在使括号序列合法的前提下,长度最短是多少,如果有多组解,输出字典序最小的

    分析

    首先最后的长度一定等于(原字符串长度+左括号与右括号数量的差值),现在我们考虑让其的字典序尽量的小

    我们预处理前缀和,’(‘为+1,’)'为-1

    我们可以发现,最终的答案一定是从序列中的某一位开始循环n

    n次,最后补上需要补足的括号数的,然后我们就只需要查找长度为n

    n的子串中合法且最小的那串

    判断合法的过程可以用hash+二分

    二分的是两个字符串第一个不一样的地方

    实际还有后缀数组做法,然后先咕了

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cctype>
    #include<cmath>
    #include<cstdlib>
    #include<queue>
    #include<ctime>
    #include<vector>
    #include<set>
    #include<map>
    #include<stack>
    using namespace std;
    #define uli long long
    const uli hsh = 13131;
    const uli hsh2 = 19260817;
    const uli mod = 1e9+7;
    const uli mod2 = 998244353;
    int n,m;
    string s,t;
    char c[1001000];
    uli pw[2001000],h[2000100],pw2[2001000],h2[2001000];
    int sum[1001000],pre[1001000],sur[1001000],le,ri;
    inline pair<uli,uli> v(int l,int r){
        return make_pair((h[r]-(l?h[l-1]:0)*pw[r-l+1]%mod+mod)%mod,
                 (h2[r]-(l?h2[l-1]:0)*pw2[r-l+1]%mod2+mod2)%mod2);
    }
    inline bool ck(int i,int j){
        int l=0,r=m;
        while(r-l>1){
          int mid=(l+r)>>1;
          if(i+mid-1>=m||j+mid-1>=m||v(i,i+mid-1)!=v(j,j+mid-1))r=mid;
            else l=mid;
        }
        if(i+r-1>=m||j+r-1>=m)return 1;
        return t[i+r-1]<t[j+r-1];
    }
    int main(){
        int i,j,k;
        scanf("%s",c);
        s=c;
        t=s+s;
        n=s.length();
        m=t.length();
        pw[0]=1;
        for(i=1;i<=m;i++)pw[i]=pw[i-1]*hsh%mod;
        h[0]=t[0];
        for(i=1;i<m;i++)h[i]=(h[i-1]*hsh+t[i])%mod;
        pw2[0]=1;
        for(i=1;i<=m;i++)pw2[i]=pw2[i-1]*hsh2%mod2;
        h2[0]=t[0];
        for(i=1;i<m;i++)h2[i]=(h2[i-1]*hsh2+t[i])%mod2;
        for(i=0;i<n;i++)sum[i]=(i?sum[i-1]:0)+(s[i]=='('?1:-1);
        pre[0]=sum[0],sur[n-1]=sum[n-1];
        for(i=1;i<n;i++)pre[i]=min(sum[i],pre[i-1]);
        for(i=n-2;i>=0;i--)sur[i]=min(sum[i],sur[i+1]);
        int maxl=1e9+7,pl=-1;
        if(sum[n-1]<0)le=-sum[n-1];
          else ri=sum[n-1];
        for(i=0;i<n;i++){
          k=(i?sum[i-1]:0);
          int w=min(sur[i]-k,sum[n-1]-k+(i?pre[i-1]:0));//重点!!!
          int ll=max(-w,max(0,-sum[n-1]));
          if(ll+ri+n<maxl){
              maxl=ll+ri+n;
              le=ll;
              pl=i;
          }else if(ll+ri+n==maxl&&ck(i,pl)){
              pl=i;
          }
        }
        for(i=1;i<=le;i++)cout<<"(";
        for(i=pl;i<n;i++)cout<<s[i];
        for(i=0;i<pl;i++)cout<<s[i];
        for(i=1;i<=ri;i++)cout<<")";
        return 0;
    }
  • 相关阅读:
    mysql多表查询的方式有哪些?
    Linq无聊练习系列4--join练习
    Linq无聊练习系列3--聚合函数练习
    Linq无聊练习系列2--select/distinct练习
    Linq无聊练习系列1--where练习
    人力资源系统遇到的问题
    sqlserver游标概念与实例全面解说
    $.cookie的用法
    JavaScript系列----正则表达式
    ASP.NET中的URL编码解码
  • 原文地址:https://www.cnblogs.com/yzxverygood/p/10368819.html
Copyright © 2011-2022 走看看