zoukankan      html  css  js  c++  java
  • [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$的个数
     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("
    ");
    86     }
    87 }
    View Code
  • 相关阅读:
    (转)Inno Setup入门(十)——操作注册表
    (转)Inno Setup入门(九)——修改安装过程中的文字显示
    (转)Inno Setup入门(八)——有选择性的安装文件
    (转)Inno Setup入门(七)——提供安装语言选项
    (转)Inno Setup入门(六)——在程序目录下创建文件夹
    (转)Inno Setup入门(五)——添加readme文件
    (转)Inno Setup入门(四)——为程序创建桌面快捷方式
    什么是REST架构(转)
    【转】敏捷开发流程
    hibernate里createSQLQuery
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13418250.html
Copyright © 2011-2022 走看看