JZOJ5811. 【NOIP提高A组模拟2018.8.13】简单的填数

这里写图片描述

Data Constraint

对于 30% 的数据,n ≤ 1000;
对于另外 30% 的数据,数据保证随机生成;
对于 100% 的数据,2 ≤ n ≤ 2 × 10^5 , 0 ≤ ai ≤ 10^5。

题解

这个很显然是特殊构造,
设一个二元组(x,l)摆在这个位置是x,而且这个是连续的第l个x。
设上界为up,下界为down。
因为要使得最终最大,所以up就是到l=2的时候就x++,
而相反down要尽可能小,所以只有当l=5时才x++。

如果遇到一个已经填了数的位置
就将up跟 (ai,2) ( a i , 2 ) 去min,因为填2之后就下一个位置就可以加1了,
那么down就跟 (ai,1) ( a i , 1 ) 去max,因为填1之后,还可以填更多的x。

判断合法就很简单,
1、上界跟下界之间没有数可以填,
2、原来已经有数的位置并不在上下界之间。
3、第一个位置填的不是1

最后,就是将整个序列还原,从最后一个位置开始,
每个数跟它后面一个数,还有上界去min,如果这个数出现的次数超过5,
就x–。

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 200003
#define M 103
#define db double
#define P putchar
#define G getchar
#define inf 998244353
#define pi 3.1415926535897932384626433832795
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

struct node
{
    int x,l;
}up[N],down[N],t,tt;

node max(node a,node b)
{
    if(a.x>b.x || (a.x==b.x && a.l>b.l))return a;
    return b;
}

node min(node a,node b)
{
    if(a.x>b.x || (a.x==b.x && a.l>b.l))return b;
    return a;
}

void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

int n,a[N],ans[N],v[N];

int main()
{
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);

    read(n);up[0].l=2;down[0].l=5;

    for(int i=1;i<=n;i++)
    {
        read(a[i]);
        t=up[i-1];
        if(t.l+1>2)t.x++,t.l=1;else t.l++;
        tt.x=a[i];tt.l=2;
        if(a[i])up[i]=min(t,tt);else up[i]=t;

        t=down[i-1];
        if(t.l+1>5)t.x++,t.l=1;else t.l++;
        tt.l=1;
        if(a[i])down[i]=max(t,tt);else down[i]=t;
    }

    if(a[1]>1)
    {
        printf("-1");
        return 0;
    }

    if(up[n].l==1)up[n].x--;
    for(int i=1;i<=n;i++)
    {
        if(a[i])
        {
            if(a[i]<down[i].x || a[i]>up[i].x)
            {
                printf("-1");
                return 0;
            }
            ans[i]=a[i];
        }
        if(up[i].x<down[i].x)
        {
            printf("-1");
            return 0;
        }
    }

    v[ans[n]=up[n].x]++;
    for(int i=n-1;i;i--)
    {
        if(!a[i])
        {
            ans[i]=min(ans[i+1],up[i].x);
            if(v[ans[i]]==5)ans[i]--;
        }
        v[ans[i]]++;
    }

    printf("%d\n",ans[n]);
    for(int i=1;i<=n;i++)
        write(ans[i]),P('\n');

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值