[nowcoder5669E]Eliminate++
枚举$a_{i}$并判断是否可行,有以下结论:若$a_{i}$可以留下来,一定存在一种合法方案使得$a_{i}$仅参与最后若干次合并,且第一次参与合并前左右都不超过2个数
证明:将大于$a_{i}$的看成1,小于$a_{i}$的看成0,将合并分为两类:
1.都在左/右区间,那么相当于删除了最右/左边的$01/10$,若存在3个数,可以将倒数第3个数与$01/10$合并去删除
2.左右区间各有1个,当达到3个后,不管是$000$和$111$还是$010$和$101$都可以预先合并再与$a_{i}$合并
根据上述结论,我们可以对两边分别求出最终结果能否为$0,00,1,11,01/10$,并判断能否组合即可
(可以保留$a_{i}$的组合方法有8种:$0-1$,$1-0$,$00-11$,$11-00$,$01/10-01/10$)
对这些结果分为两类进行判断:
1.全部相同(即$0/00/1/11$):以0为例,不断插入一个数字,要合并当且仅当以$111$或$10$为结尾(特别的,如果$10$是最后两个数,那么就无解,也可以删除掉),证明略(贪心策略中$10$消除是为了更好地消除$111$)
具体维护方法:根据贪心,可以发现插入并合并完后一定是若干个$0$和不超过2个$1$,对0和1的个数进行维护,最后只需要判断0的个数是否比1的多即可
2.$01/10$,首先长度必须要为偶数,之后考虑如果$0$和$1$个数相同,那么一定存在相邻的$01/10$且必然有别的数(否则就已经完成了),不断消除$01/10$即可
假设$1$的个数比$0$的个数多,按照第一种方案的贪心,有解必然存在一次合并后满足$0$的个数和$1$的个数一样多(包括未插入的部分),即最终状态下$0$的个数不小于比$1$的个数,证明略
但这样的复杂度为$o(n^{2})$,需要优化:
从小到大枚举$a_{i}$,那么每一次相当于将一个位置上的$1$变成$0$,考虑要维护哪些信息:1.两种贪心时的最终状态;2.$0$的个数和$1$的个数
View Code
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1000005 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1) 7 struct sta{ 8 int x,y; 9 }; 10 struct ji{ 11 int k; 12 sta a[2]; 13 }o,o0,o1; 14 struct type{ 15 ji p0,p1; 16 }f[N<<2]; 17 int t,n,a[N],id[N],ans[N]; 18 sta merge(sta x,sta y){ 19 sta z; 20 z.x=x.x+max(y.x-x.y,0); 21 z.y=(y.y+max(x.y-y.x,0)-1)%2+1; 22 return z; 23 } 24 type merge(type x,type y){ 25 type z; 26 z.p0.k=x.p0.k+y.p0.k; 27 z.p1.k=x.p1.k+y.p1.k; 28 z.p0.a[0]=merge(x.p0.a[0],y.p0.a[0]); 29 z.p0.a[1]=merge(y.p0.a[1],x.p0.a[1]); 30 z.p1.a[0]=merge(x.p1.a[0],y.p1.a[0]); 31 z.p1.a[1]=merge(y.p1.a[1],x.p1.a[1]); 32 return z; 33 } 34 35 void build(int k,int l,int r){ 36 if (l==r){ 37 f[k]=type{o0,o1}; 38 return; 39 } 40 build(L,l,mid); 41 build(R,mid+1,r); 42 f[k]=merge(f[L],f[R]); 43 } 44 void update(int k,int l,int r,int x){ 45 if (l==r){ 46 f[k]=type{o1,o0}; 47 return; 48 } 49 if (x<=mid)update(L,l,mid,x); 50 else update(R,mid+1,r,x); 51 f[k]=merge(f[L],f[R]); 52 } 53 type query(int k,int l,int r,int x,int y){ 54 if ((l>y)||(x>r))return type{o,o}; 55 if ((x<=l)&&(r<=y))return f[k]; 56 return merge(query(L,l,mid,x,y),query(R,mid+1,r,x,y)); 57 } 58 bool pd(type k,int p,int x){ 59 if (!x)return k.p0.a[p].x>k.p0.a[p].y; 60 if (x==1)return k.p1.a[p].x>k.p1.a[p].y; 61 if (x==2){ 62 if (k.p0.k==k.p1.k)return 1; 63 if (k.p0.k<k.p1.k)return k.p0.a[p].x>=k.p0.a[p].y; 64 return k.p1.a[p].x>=k.p1.a[p].y; 65 } 66 } 67 int main(){ 68 o0.a[0].y=o0.a[1].y=1; 69 o1.k=o1.a[0].x=o1.a[1].x=1; 70 scanf("%d",&t); 71 while (t--){ 72 scanf("%d",&n); 73 for(int i=1;i<=n;i++){ 74 scanf("%d",&a[i]); 75 ans[i]=0; 76 id[a[i]]=i; 77 } 78 build(1,1,n); 79 for(int i=1;i<=n;i++){ 80 update(1,1,n,id[i]); 81 type x=query(1,1,n,1,id[i]-1),y=query(1,1,n,id[i]+1,n); 82 if ((pd(x,0,0))&&(pd(y,1,1))||(pd(x,0,1))&&(pd(y,1,0))||(pd(x,0,2))&&(pd(y,1,2)))ans[id[i]]=1; 83 } 84 for(int i=1;i<=n;i++)printf("%d",ans[i]); 85 printf("\n"); 86 } 87 }