码迷,mamicode.com
首页 > 其他好文 > 详细

AGC028E High Elements

时间:2020-02-07 20:42:35      阅读:76      评论:0      收藏:0      [点我收藏+]

标签:undo   一个   class   span   题目   putchar   lse   while   tchar   

Link
我们称自身为前缀最大值的位置为上升位,称\(P\)中原油的上升位为原上升位,称\(X,Y\)中不是\(P\)中的上升位的上升位为新上升位
因为题目是要求字典序最小,因此我们可以高位贪心,能选\(0\)则选\(0\)
显然\(P\)的上升位到了\(X,Y\)中一定还是上升位,但是\(X,Y\)中可能会有一些新上升位。
先给出一个结论:

如果存在合法方案,那么一定存在一组合法方案,使得\(X\)或者\(Y\)不包含新上升位。
证:
\(X,Y\)中都包含新上升位,那么我们交换这两个位置,这样这两个新上升位就都被消掉了。(因为一个新上升位在\(P\)中一定存在一个不让它成为上升位的元素,而这个元素肯定在另一个串里面)

那么我们先考虑\(X\)不含新上升位的情况。
假设目前要对第\(i\)位做决策,记\(X\)中有\(sx\)个上升位,\(Y\)中有\(sy\)个上升位,\([i+1,n]\)\(x\)个原上升位。设\(Y\)接下来要拿到\(y\)个原上升位,那么\(X\)接下来就要拿到\(x-y\)个原上升位。设\(Y\)接下来要拿到\(m\)个新上升位。
那么可以列出等式:\(sx+x-y=sy+y+m\),移项得到\(sx+x-sy=2y+m\)
此时等式左边是一个常量,问题转化为在\([i+1,n]\)中选一个序列,原上升位的贡献为\(2\),新上升位的贡献为\(1\)
显然如果能够凑出\(x\),那么一定可以凑出\(x-2\),因此用一个带撤销的BIT维护一下奇偶的原序列最值即可。

#include<cstdio>
#include<cctype>
#include<cstring>
#include<utility>
#include<algorithm>
#define fi first
#define se second
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}
using IO::read;
using std::pair;
using pi=pair<int,int>;
const int N=200007,M=5000007;
int n,a[N],val[N],sum[N],mx[2],mn[2][2],c[2][2];pi pos[N];
char ans[N];
struct BIT
{
    int t[N],top;pi stk[M];
    void add(int p,int v){for(;p<=n;p+=p&-p)stk[++top]={p,t[p]},t[p]=std::max(t[p],v);}
    int ask(int p){int r=-1e9;for(p=std::min(p,n);p;p^=p&-p)r=std::max(r,t[p]);return r;}
    void undo(int p){for(;top>p;--top)t[stk[top].fi]=stk[top].se;}
}t[2];
int main()
{
    n=read();
    for(int i=1,x=n+1;i<=n;++i) if(x>(a[i]=n+1-read())) x=a[i],val[i]=2; else val[i]=1;
    memset(t[1].t,0x8f,sizeof t[1].t);
    for(int i=n;i;--i) sum[i]=sum[i+1]+(val[i]==2);
    for(int i=n;i^1;--i)
    {
    for(int j=0;j<2;++j) mx[j]=std::max(0,t[j].ask(a[i]));
    for(int j=0,x;j<2;++j) x=mx[j]+val[i],t[x&1].add(a[i],x);
    pos[i]={t[0].top,t[1].top};
    }
    mn[0][0]=mn[0][1]=n+1;
    for(int i=1,now=0;i<=n;++i)
    {
        now^=1;
        if(i<n) t[0].undo(pos[i+1].fi),t[1].undo(pos[i+1].se);
    for(int j=0,f;j<2;++j)
    {
        memcpy(mn[now],mn[now^1],8),memcpy(c[now],c[now^1],8);
        if(a[i]<mn[now^1][j]) mn[now][j]=a[i],c[now][j]=c[now^1][j]+1;
        f=i==n? (c[now][0]==c[now][1]):0;
        if(i<n)
        {
        for(int k=0,x;k<2;++k)
        {
            x=c[now][k]-c[now][k^1]+sum[i+1];
            if(x>=0&&x<=t[x&1].ask(mn[now][k^1])) {f=1;break;}
        }
        }
        if(f) {ans[i]='0'+j;break;}
        }
        if(!ans[i]) return !printf("-1");
    }
    for(int i=1;i<=n;++i) putchar(ans[i]);
}

AGC028E High Elements

标签:undo   一个   class   span   题目   putchar   lse   while   tchar   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12274328.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!