[cf1610G]AmShZ Wins a Bet

Keywords: CodeForces

The operation on $t $inserts a pair of parentheses in $t $, and the reverse process deletes a pair of parentheses

In other words, $s $can be obtained by $t $if and only if $t $can be obtained by deleting several pairs of parentheses in $s $, that is, the problem is to find $\ min t$

Conclusion $\ min t can be obtained by deleting several legitimate substrings (referring to the sequence of legal parentheses) in $s $$

Considering the original process of obtaining $\ min t $, for each pair of deleted parentheses, the middle part of the two parentheses must also be deleted (otherwise, the deleted left parenthesis can be made more right or the right parenthesis can be made more left, which obviously does not increase the dictionary order)

Further, consider a very long deletion interval. When the brackets are deleted, the corresponding brackets are always within this interval (otherwise they are not very long). Therefore, a legal bracket sequence is formed, and these intervals can be deleted respectively

On the other hand, it is obvious that the legal substring can also be disassembled into several pairs of parentheses, so we might as well take this as a problem

In addition, the deletion of several legitimate substrings in the legal bracket sequence is obviously still legal, that is, the deletion order does not affect (arbitrary)

Consider dp and make $ans_{i} $is the answer of $s[i,|s |] $and it is not difficult to get $ans_{i} = \ min (s {I} + ans {I + 1}, \ min {s [I, J) legal} ans {J})$

Note that the shortest non empty substring to the right of $i $is $s [i, next {i}) $. Note that if $s[i,j) $is legal, $s [next {i}, J) $is also legal, that is, $ans {next {i} $already includes the latter. You may wish to transfer only $J = next {i} $, that is, $ans {i} = \ min (s {i} + ans {i + 1}, ans {next {i})$

Next, consider how to implement this process:

It is recommended that a tree take $n+1 $as the root, and the characters from $i $to the root path form $ans {i} $(similar to trie tree)

Consider finding $ans {i} $. Initially, $s {i} + ans {i+1} $is transferred, that is, $i $is the son of $i+1 $, and the character on the side is $s {i}$

Next, if the string from $next {i} $to the root path is smaller than $i $, take $i $as the son of the father of $next {i} $and the character on the side is $s {next {i}}$

For comparison, note that new leaves are always added. Use multiplication + hash to find the first different position

The time complexity is $o(n\log n) $, which can be

(the code is implemented as $o(n\log^{2}n) $, and the two points can be removed by direct comparison in multiplication)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 300005
 4 #define L 19
 5 #define ull unsigned long long
 6 int n,st[N],nex[N],pos[N],dep[N],fa[N][L];
 7 ull mi[N],Hash[N][L];
 8 char s[N];
 9 int get_pos(int k,int d){
10     for(int i=0;i<L;i++)
11         if (d&(1<<i))k=fa[k][i];
12     return k;
13 }
14 ull get_Hash(int k,int d){
15     ull ans=0;
16     for(int i=0,s=0;i<L;i++)
17         if (d&(1<<i)){
18             ans=ans+Hash[k][i]*mi[s];
19             k=fa[k][i],s|=(1<<i);
20         }
21     return ans;
22 }
23 void add(int k,int f,int p){
24     pos[k]=p,dep[k]=dep[f]+1;
25     fa[k][0]=f,Hash[k][0]=p;
26     for(int i=1;i<L;i++){
27         fa[k][i]=fa[fa[k][i-1]][i-1];
28         Hash[k][i]=Hash[k][i-1]+Hash[fa[k][i-1]][i-1]*mi[1<<i-1];
29     }
30 }
31 bool cmp(int x,int y){
32     int l=0,r=min(dep[x],dep[y]);
33     while (l<r){
34         int mid=(l+r+1>>1);
35         if (get_Hash(x,mid)==get_Hash(y,mid))l=mid;
36         else r=mid-1;
37     }
38     x=get_pos(x,l),y=get_pos(y,l);
39     return pos[x]<pos[y];
40 }
41 int main(){
42     mi[0]=1;
43     for(int i=1;i<N;i++)mi[i]=3*mi[i-1];
44     scanf("%s",s+1),n=strlen(s+1);
45     for(int i=1;i<=n;i++)
46         if (s[i]=='(')st[++st[0]]=i;
47         else{
48             if (st[0])nex[st[st[0]--]]=i+1;
49         }
50     dep[0]=-1;
51     for(int i=n;i;i--){
52         add(i,i+1,(s[i]==')')+1);
53         if ((nex[i])&&(cmp(nex[i],i)))add(i,fa[nex[i]][0],pos[nex[i]]);
54     }
55     for(int i=1;fa[i][0];i=fa[i][0]){
56         if (pos[i]==1)printf("(");
57         else printf(")");
58     }
59     printf("\n");
60     return 0;
61 }


Posted by Zilvermeeuw on Fri, 03 Dec 2021 09:15:53 -0800