Codeforces 1150
1150 C
题意
给你一个由 \(1,2\) 组成的数组,要你重新排列这个数组,使得它的所有是质数的前缀和最长。 \((1\le n\le 200000)\)
Examples
input
5
1 2 1 2 1
output
1 1 1 2 2
input
9
1 1 2 1 1 1 2 1 1
output
1 1 1 2 1 1 1 2 1
解
一个一个往上去凑就行了,优先选2。
1150 D
题意
给你一个长 \(\le 10^5\) 的文本串,现在你有三个模式串,每个长度 \(\le 250\) ,初始为空,现在你有两种操作:
+ i c
,给串 \(i\) 末尾加上一个字符 \(c\)- i
,删除 \(i\) 末尾的字符
现在在每次操作后询问三个串是否分别对应文本串中三个不相交的子序列。
Examples
input
6 8
abdabc
+ 1 a
+ 1 d
+ 2 b
+ 2 c
+ 3 a
+ 3 b
+ 1 c
- 2
output
YES
YES
YES
YES
YES
YES
NO
YES
input
6 8
abbaab
+ 1 a
+ 2 a
+ 3 a
+ 1 b
+ 2 b
+ 3 b
- 1
+ 2 z
output
YES
YES
YES
YES
YES
NO
YES
NO
解
每次询问可以在 \(O(len^2)(len\le 250)\) 时间内解决,考虑 \(n^2\) dp。
我们设 \(nxt[i][c]\) 为字符 \(c\) 在位置 \(i\) 后第一次出现的位置。
先考虑 \(n^3\) 做法。
设 \(dp[i][j][k]\) 表示第一个串匹配到 \(i\) ,第二个串匹配到 \(j\) ,第三个串匹配到 \(k\) ,三个串对应的子序列中末尾最前面的末尾的位置。
这样的话全部转移是 \(n^3\) 的。
但是对于每个询问我们发现只需要用 \(n^2\) 去更新对应的dp值。
所以复杂度为 \(O(qlen^2)\)
1150 E
题意
给你一个括号序列,有 \(q(\le 10^5)\) 次操作,每次操作交换两个括号,问每一步操作后括号序列对应的括号树的直径。
Examples
input
5 5
(((())))
4 5
3 4
5 6
3 6
2 5
output
4
3
3
2
4
4
input
6 4
(((())()))
6 7
5 4
6 4
7 4
output
4
4
4
5
3
解
线段树维护括号区间。
树的直径其实就是 \(\max(dep[u]+dep[v]-2*dep[lca(u,v)])\) 。
对于每一个区间,我们记
- \(delta\) 最左侧括号深度 \(-\) 最右侧括号深度。
- \(mx\) 即 \(dep[u]\) ,最深的节点的深度
- \(m\) 即 $$dep[lca]$ ,最浅的节点的深度
- \(lm\) 即 \(dep[u]-2*dep[lca]\)
- \(mr\) 即 \(-2*dep[lca]+dep[v]\)
- \(lmr\) 即 \(dep[u]+dep[v]-2*dep[lca]\)
询问时询问线段树根节点的 \(lmr\) 值。
Code
#include<bits/stdc++.h>
using namespace std;
const int maxn=200003,INF=1050000000;
struct node{int delta,mx,m,lm,mr,lmr;}t[maxn<<2];
int n;
char s[maxn];
node operator +(node t2,node t3){
node t1;
t1.delta=t2.delta+t3.delta;
t3.mx+=t2.delta;
t3.m-=2*t2.delta;
t3.lm-=t2.delta;
t3.mr-=t2.delta;
t1.mx=max(t2.mx,t3.mx);
t1.m=max(t2.m,t3.m);
t1.lm=max(max(t2.lm,t3.lm),t2.mx+t3.m);
t1.mr=max(max(t2.mr,t3.mr),t2.m+t3.mx);
t1.lmr=max(max(t2.lmr,t3.lmr),max(t2.mx+t3.mr,t2.lm+t3.mx));
return t1;
}
void build(int p,int l,int r){
if(l==r){
t[p].mx=t[p].delta=(s[l]=='('?1:-1);
t[p].m=-2*t[p].mx;
t[p].lm=t[p].mr=-INF;
t[p].lmr=-INF;
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
t[p]=t[p<<1]+t[p<<1|1];
}
void change(int p,int l,int r,int pos,char k){
if(l==r){
int f=(k=='('?2:-2);
t[p].delta+=f;
t[p].mx+=f;
t[p].m-=2*f;
t[p].lm-=f;
t[p].mr-=f;
return;
}
int mid=(l+r)>>1;
if(pos<=mid)change(p<<1,l,mid,pos,k);
else change(p<<1|1,mid+1,r,pos,k);
t[p]=t[p<<1]+t[p<<1|1];
}
int query(){
return max(t[1].mx,t[1].lmr);
}
int main(){
int Q;
scanf("%d%d%s",&n,&Q,s+1);
n=(n-1)<<1;
build(1,1,n);
printf("%d\n",query());
while(Q--){
int x,y;
scanf("%d%d",&x,&y);
change(1,1,n,x,s[x]=(s[x]=='('?')':'('));
change(1,1,n,y,s[y]=(s[y]=='('?')':'('));
printf("%d\n",query());
}
return 0;
}
1149 D
考虑删掉所有的b边,剩下若干个连通块,我们只考虑连接两个不同连通块的b边,最后bfs跑最短路,用状压记录是否已经访问了该连通块。连通块大小 \(\le 3\) 的,不用记到状压里去,手模一下就知道了。然后复杂度就对了。