AGC028 E - High Elements


有一个排列\(p\),你要分成两个子序列\(A,B\),满足\(A,B\)的LIS长度相等。设\(S\)是一个\(01\)序列,\(S_i=0\)当且仅当\(i\)被分到\(A\)中。求满足条件的字典序最小的\(S\)。

显然算法大约为贪心考虑每一位是否可以是\(0\)。

有一个结论:

\(p\)上升点是\(p\)中lis中的点,上升点是指在这个子序列lis中的点,上升点但不是\(p\)上升点称为新上升点。

  1. 新上升点是上升点是因为它前面的大于它的点都分到了另一个子序列。所以如果将新上升点放到另一个子序列就不是新上升点了

  2. 一定可以做到有一个序列中没有新上升点,如果不满足,考虑\(A,B\)各有一个新上升点,把它们放到另外一个子序列中,就都少了一个上升点,数量还是相等。钦定这个没有新上升点的子序列是\(A\)。

考虑\([i+1,n]\)是否可以盒子安排使得\(A,B\)LIS长度相等。设\([1,i]\)中\(A\)上升点数量为\(la\),\(B\)的为\(lb\),\([i+1,n]\)中有\(k\)个\(p\)上升点。

如果\(k\)个\(p\)上升点\(B\)分了\(pb\)个,\(A\)分了\(k-pb\)个,而且\(B\)中还有\(s\)个新上升点,那么可以根据\(A,B\)上升点相同列式子:

\[la+k-pb=lb+pb+s
\]

\[la+k-lb=2pb+s
\]

左边是常数,设为\(c\)。现在只需要知道能不能在\([i+1,n]\)中选一个上升子序列权值和为\(c\)。\(p\)上升点权值为\(2\),新上升点为\(1\)。

这个直接线段树一下就行了。

#include<bits/stdc++.h>
#define il inline
#define vd void
typedef long long ll;
il ll gi(){
ll x=0,f=1;
char ch=getchar();
while(!isdigit(ch))f^=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f?x:-x;
}
int n,p[200010];
int f[2][200010],ismx[200010];
struct segtree{
#define mid ((l+r)>>1)
int rt[200010],ls[6000010],rs[6000010],mx[6000010],cnt;
il vd update(int&x,int l,int r,const int&p,const int&d){
++cnt;ls[cnt]=ls[x],rs[cnt]=rs[x],mx[cnt]=mx[x];x=cnt;
if(l==r){mx[x]=d;return;}
if(d>mx[x])mx[x]=d;
if(p<=mid)update(ls[x],l,mid,p,d);
else update(rs[x],mid+1,r,p,d);
}
il int query(int x,int l,int r,const int&L){
if(L<=l)return mx[x];
if(L<=mid)return std::max(query(ls[x],l,mid,L),query(rs[x],mid+1,r,L));
else return query(rs[x],mid+1,r,L);
}
#undef mid
}T0,T1;
char ans1[200010],ans2[200010];
il int Query(int c,int l,int p){
if(l>n)return c?-1e9:0;
if(!c)return T0.query(T0.rt[l],1,n,p);
else return T1.query(T1.rt[l],1,n,p);
}
int main(){
#ifdef XZZSB
freopen("in.in","r",stdin);
freopen("out.out","w",stdout);
#endif
n=gi();
for(int i=1;i<=n;++i)p[i]=gi();
int la1=0,lb1=0,la2=0,lb2=0,mxa1=0,mxa2=0,mxb1=0,mxb2=0,rest=0;
for(int i=1,mx=0;i<=n;++i)if(p[i]>mx)mx=p[i],ismx[i]=1,++rest;
memset(T1.mx,-63,sizeof T1.mx);
for(int i=n;i;--i){
T0.rt[i]=T0.rt[i+1];T1.rt[i]=T1.rt[i+1];
if(ismx[i])f[0][i]=T0.query(T0.rt[i],1,n,p[i])+2,f[1][i]=T1.query(T1.rt[i],1,n,p[i])+2;
else f[0][i]=T1.query(T1.rt[i],1,n,p[i])+1,f[1][i]=T0.query(T0.rt[i],1,n,p[i])+1;
T0.update(T0.rt[i],1,n,p[i],f[0][i]);T1.update(T1.rt[i],1,n,p[i],f[1][i]);
}
auto adda1=[&](int x){if(x>mxa1)++la1,mxa1=x;};
auto adda2=[&](int x){if(x>mxa2)++la2,mxa2=x;};
auto addb1=[&](int x){if(x>mxb1)++lb1,mxb1=x;};
auto addb2=[&](int x){if(x>mxb2)++lb2,mxb2=x;};
for(int i=1;i<=n;++i){
int c=la1+rest-lb1+(p[i]>mxa1)-ismx[i];
if(c>=0&&Query(c&1,i+1,mxb1)>=c)ans1[i]='0',adda1(p[i]);
else ans1[i]='1',addb1(p[i]);
c=la2+rest-lb2-(p[i]>mxb2)-ismx[i];
if(c>=0&&Query(c&1,i+1,std::max(p[i],mxb2))>=c)ans2[i]='0',addb2(p[i]);
else ans2[i]='1',adda2(p[i]);
if(ismx[i])--rest;
}
if(la1==lb1&&la2==lb2){
if(strcmp(ans1+1,ans2+1)<0)printf("%s",ans1+1);
else printf("%s",ans2+1);
}else if(la1==lb1)printf("%s",ans1+1);
else if(la2==lb2)printf("%s",ans2+1);
else puts("-1");
return 0;
}

AGC028 E - High Elements的更多相关文章

  1. js Form.elements[i]的使用实例

    function pdf(){    //一个html里面可能存在多个form,所以document.form[0]指的是第一个form,document.form[1]返回就是第二个form,如果没 ...

  2. View and Data API Tips: Hide elements in viewer completely

    By Daniel Du With View and Data API, you can hide some elements in viewer by calling "viewer.hi ...

  3. [LeetCode] Minimum Moves to Equal Array Elements II 最少移动次数使数组元素相等之二

    Given a non-empty integer array, find the minimum number of moves required to make all array element ...

  4. [LeetCode] Minimum Moves to Equal Array Elements 最少移动次数使数组元素相等

    Given a non-empty integer array of size n, find the minimum number of moves required to make all arr ...

  5. [LeetCode] Top K Frequent Elements 前K个高频元素

    Given a non-empty array of integers, return the k most frequent elements. For example,Given [1,1,1,2 ...

  6. [LeetCode] Remove Linked List Elements 移除链表元素

    Remove all elements from a linked list of integers that have value val. Example Given: 1 --> 2 -- ...

  7. Chrome 开发工具之Elements

    友情提示:全文图片高能,如使用手机阅读,请确保在wifi情况下或者流量充足.图片有点渣,也算辛苦做出来的,请别嫌弃- Elements面板主要展示当前页面的组织结构,在如今的应用程序中,HTML页面初 ...

  8. T-SQL Recipes之Separating elements

    Separating elements Separating elements is a classic T-SQL challenge. It involves a table called Arr ...

  9. POJ2167Irrelevant Elements[唯一分解定理 组合数 杨辉三角]

    Irrelevant Elements Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 2407   Accepted: 59 ...

随机推荐

  1. NET Core 3.0 AutoFac替换内置DI的新姿势

    原文:NET Core 3.0 AutoFac替换内置DI的新姿势 .NET Core 3.0 和 以往版本不同,替换AutoFac服务的方式有了一定的变化,在尝试着升级项目的时候出现了一些问题. 原 ...

  2. 使用KONG网关实现接口迁移的灰度验证

    在我们对一个API站点进行微服务化的过程中,使用KONG网关可以实现以下几个效果: 1. 业务线无感知,其实内部已经被Kong转到其他站点上执行了,这对业务线特别友好. 2. 可以实现租户级/接口级灰 ...

  3. Object类的toString()和equals()方法

    我们知道,Object类是所有类的父类,因此也被称为根类.祖先.那么,我们就来看一看Object类的最常用的两个方法是如何用的. 1.toString方法: Object类的toString()方法默 ...

  4. 2019 央视网java面试笔试题 (含面试题解析)

    本人3年开发经验.18年年底开始跑路找工作,在互联网寒冬下成功拿到阿里巴巴.今日头条.央视网等公司offer,岗位是Java后端开发,最终选择去了央视网. 面试了很多家公司,感觉大部分公司考察的点都差 ...

  5. 【转载】C#中double.TryParse方法和double.Parse方法的异同之处

    在C#编程过程中,double.TryParse方法和double.Parse方法都可以将字符串string转换为double类型,但两者还是有区别,最重要的区别在于double.TryParse方法 ...

  6. js计算hashcode

    String.prototype.hashCode = function(){ var hash = 0; for (var i = 0; i < this.length; i++) { var ...

  7. Node.js实现用户评论社区(体验前后端开发的乐趣)

    前面 接着上一节的内容来,今天我们要完成一个用Node开发后台服务器,实现一个简单的用户评论社区.可以先看下效果图: 开始 建立项目文件夹comment-list,在里面新建一个public文件夹,p ...

  8. region、xld有对应的字符串时,将region、xld按照行或列排序的算法实现

    用Halcon解码时,如果一张图里面有多个码,它通常可以把这些码都解出来,并且生成对应的解码结果字符串元组(也就是下面的DecodedDataStrings),如果有多个码,那么该元组就有多个元素. ...

  9. Oracle 11g新特性direct path read引发的系统停运故障诊断处理

    黎俊杰 | 2016-07-28 14:37 声明:部分表名为了脱敏而用XX代替 1.故障现象 (1)一个业务系统输入用户名与密码后无法进入首页,表现为一直在运行等待,运行缓慢 (2)整个系统无法正常 ...

  10. windows下binlog问题解决

    1.先确定mysql是否开启了binlog show binary logs; 默认情况下是不开启的 2.如何开启 在my.ini配置下添加两个参数 # Binary Logginglog-bin=m ...