Codeforces VK Cup 2015 A.And Yet Another Bracket Sequence(后缀数组+平衡树+字符串)

这题做得比较复杂。。应该有更好的做法

题目大意:

有一个括号序列,可以对其进行两种操作:

·        向里面加一个括号,可以在开头,在结尾,在两个括号之间加。

·        对当前括号序列进行循环移动,即把最后一个括号拿到开头来。

上述两种操作可以做任意次,要求添加最少的括号使得原序列变成一个合法括号序列。如果有多种可能,输出字典序最小的那一个。"(" < ")"。

题解:

首先计算左括号和右括号的数量,可以知道,不妨假设左括号的数量大于右括号

那么最少的方案就是在字符串右侧补充右括号,使得左括号的数量等于右括号的数量。

但是一个方案是否可行,要使得前面的每个前缀,都满足条件左括号的数量大于右括号

如果不满足,就循环移动即可,通过循环移动就一定会找到一个方案。

要输出字典序最小的方案,就需要后缀数组了

把字符串循环复制一遍,做后缀数组,那么就知道每个方案的排名

找最小且可行的方案输出即可。

另一种情况是左括号的数量小于右括号,也是同理的。

关于如何判断是否可行,这里是用的平衡树

写出每个位置的条件,每移动一次,对所有的条件影响都是相同的,所以用平衡树维护这些条件即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <map>
#include <set>
using namespace std;
const int maxn = 2e6 + 1000;
int Wa[maxn], Wb[maxn], Wv[maxn], Ws[maxn], sa[maxn];
int Rank[maxn];
int height[maxn];
set<int> S;
map<int, int> M;
vector<int> V;
int a[maxn];
int cmp(int *r, int a, int b, int l)
{
    return r[a]==r[b] && r[a+l]==r[b+l];
}
void get_sa(int *r, int *sa, int n, int m)
{
    int i,j,p,*x=Wa,*y=Wb,*t;
    for(i=0; i<m; i++) Ws[i]=0;
    for(i=0; i<n; i++) Ws[x[i]=r[i]]++;
    for(i=1; i<m; i++) Ws[i]+=Ws[i-1];
    for(i=n-1; i>=0; i--) sa[--Ws[x[i]]]=i;
    for(p=1,j=1; p<n; j*=2,m=p)
    {
        for(p=0,i=n-j; i<n; i++) y[p++]=i;
        for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
        for(i=0; i<n; i++) Wv[i]=x[y[i]];
        for(i=0; i<m; i++) Ws[i]=0;
        for(i=0; i<n; i++) Ws[Wv[i]]++;
        for(i=1; i<m; i++) Ws[i]+=Ws[i-1];
        for(i=n-1; i>=0; i--) sa[--Ws[Wv[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
}
void get_height(int *r, int *sa, int n)
{
    int i, j, k=0;
    for(i=1; i<=n; i++) Rank[sa[i]]=i;
    for(i=0; i<n; height[Rank[i++]]=k)
        for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++);
}

void Hinsert(int x){
    if(M[x] == 0) S.insert(x);
    M[x]++;
}
void Herase(int x){
    if(M[x] == 1) S.erase(x);
    M[x]--;
}
char str[maxn];
int tr, tl;
int main()
{
    cin>>str;
    int n = strlen(str), nl = 0, nr = 0;
    for(int i = 0; i < n; i++){
        if(str[i] == ‘(‘) nl++, str[i] = 1;
        else nr++, str[i] = 2;
    }
    if(nl < nr){
        tl = 0;
        for(int i = n-1; i >= 0; i--){
            if(str[i] == 1) tl++;
            a[i] = 2*tl-(n-i);
            Hinsert(-a[i]);
        }
        tl = 0;
        for(int i = n-1; i >= 0; i--){
            if(-(*S.begin()) <= -(n-i-1)+2*tl) V.push_back(i);
            Herase(-a[i]);
            if(str[i] == 1) tl++;
            Hinsert(-(2*nl-n-(n-i)+2*tl));
        }
        int N = 2*n-1;
        for(int i = 0; i < n; i++) a[i] = str[i];
        for(int i = n; i < N; i++) a[i] = str[i-n];
        get_sa(a, sa, N+1, 4);
        for(int i = 1; i <= N; i++) Rank[sa[i]] = i;
        int maxr = N+100, Kr = 0;
        for(auto i : V){
            if(i+1 >= N) break;
            if(Rank[i+1] < maxr){
                maxr = Rank[i+1];
                Kr = i+1;
            }
        }
        a[N] = a[N-n];
        for(int i = 0; i < nr-nl; i++) printf("(");
        for(int i = Kr; i < Kr+n; i++) printf("%c", a[i] == 2 ? ‘)‘ : ‘(‘);
    } else {
        tr = 0;
        for(int i = 0; i < n; i++){
            if(str[i] == 2) tr++;
            a[i] = 2*tr-i-1;
            Hinsert(-a[i]);
        }
        tr = 0;
        for(int i = 0; i < n; i++){
            if(-(*S.begin()) <= -i+2*tr) V.push_back(i);
            Herase(-a[i]);
            if(str[i] == 2) tr++;
            Hinsert(-(2*nr-n-i-1+2*tr));
        }
        int N = 2*n-1;
        for(int i = 0; i < n; i++) a[i] = str[i];
        for(int i = n; i < N; i++) a[i] = str[i-n];
        get_sa(a, sa, N+1, 4);
        for(int i = 1; i <= N; i++) Rank[sa[i]] = i;
        int maxr = N+100, Kr = 0;
        for(auto i : V){
            if(Rank[i] < maxr){
                maxr = Rank[i];
                Kr = i;
            }
        }
        for(int i = Kr; i < Kr+n; i++) printf("%c", a[i] == 2 ? ‘)‘ : ‘(‘);
        for(int i = 0; i < nl-nr; i++) printf(")");
    }
}
时间: 2024-08-04 03:32:48

Codeforces VK Cup 2015 A.And Yet Another Bracket Sequence(后缀数组+平衡树+字符串)的相关文章

Codeforces VK Cup 2015 Wild Card Round 1 (AB)

比赛链接:http://codeforces.com/contest/522 A. Reposts time limit per test:1 second memory limit per test:256 megabytes One day Polycarp published a funny picture in a social network making a poll about the color of his handle. Many of his friends started

VK Cup 2015 - Round 1 E. Rooks and Rectangles 线段树 定点修改,区间最小值

E. Rooks and Rectangles Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/524/E Description Polycarpus has a chessboard of size n × m, where k rooks are placed. Polycarpus hasn't yet invented the rules of the game

【codeforces VK Cup Round 1】BDE题解

B. Group Photo 2 (online mirror version) time limit per test2 seconds memory limit per test256 megabytes inputstandard input outputstandard output Many years have passed, and n friends met at a party again. Technologies have leaped forward since the

Codeforces VK Cup Finals #424 Div.1 C. Bamboo Partition(数论)

题目要求符合以下条件的最大的d 化简得 注意到 最多只有2*sqrt(a[i]-1)种取值,也就是一共最多有n*sqrt(10^19)种取值,于是枚举一下d,计算出符合上上式的最大的d更新答案,然后d跳跃到下一个取值 效率O(n²sqrt(10^9)) #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=110,inf=1e9; ll n,k,ans,r; ll a[maxn]; vo

Codeforces VK Cup Finals #424 Div.1 A. Office Keys(DP)

显然是不可能交叉取钥匙的,于是把钥匙和人都按坐标排序就可以DP了 钥匙可以不被取,于是f[i][j]表示前i个钥匙被j个人拿的时间 f[i][j]=min(f[i-1][j],max(f[i-1][j-1],abs(b[i]-a[j])+abs(P-b[i])); #include<bits/stdc++.h> #define ll long long using namespace std; const int maxn=1010,inf=2e9; int n,k,p; int a[maxn

codeforces Looksery Cup 2015 H Degenerate Matrix 二分 注意浮点数陷阱

#include <cstdio> #include <cstring> #include <algorithm> #include <string> #include <cmath> #include <iostream> using namespace std; bool fun(double l1,double r1,double l2,double r2){ return (l1 <= r2 && l1

codeforces VK cup 2016-round 1 D.Bear and Contribution

题意大概就是有n个数字,要使至少有k个相同,可以花费b使一个数+5,可以花费c使一个数+1,求最小花费. 要对齐的数肯定是在[v,v+4]之间,所以分别枚举模为0~4的情况就可以了. 排序一下,然后化绝对为相对 例如有 3 6 8 14这4个数,模4, 耗费分别为c+2b 3c+b c+b 0 可以-2b(移动到14时=2*5+4,倍率2)变成c 3c-b c-b -2b 就是说每次都取倍率然后减其花费压入优先队列,若元素数量大于k就弹出最大的那个就可以了 /*没时间自己写个就把其他人的题解搞来

VK Cup 2015 - Round 2 B. Work Group

题解: 树形dp 首先开始做时我以为只要贪心选取就可以了... 后来发现根节点可以不用选,而选和为奇数的满足条件的子节点. 所以需要重新构建状态 dp[u][0]表示满足条件的以u为根节点的子树中,节点数为偶数的最大值 dp[u][0]表示满足条件的以u为根节点的子树中,节点数为奇数的最大值 最开始不选根节点.dp[u][0]=0,dp[u][1]为-INF(不存在) 每次加子节点v时 1.偶可以由偶(u)+偶(v),奇(u)+奇(v)更新 2.奇可以由奇(u)+奇(v),奇(u)+奇(v)更新

VK Cup 2015 - Finals, online mirror

F. Clique in the Divisibility Graph 题目传送:Clique in the Divisibility Graph 解法:筛法+DP AC代码: #include <map> #include <set> #include <cmath> #include <deque> #include <queue> #include <stack> #include <cstdio> #include