联赛模拟17_简单的填数
贪心
up[i]记录保证序列值最大的情况下的信息
up.val:取值
up.len: a[i]是第几个
down相反
我们将每个数的两种边界可能情况 1->n 更新出来,a[n]取上边界,倒着恢复序列即可
对于每次有值的点,在保证符合的前提下尽量满足down和up的趋势,同时检验即可。
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn=2e5+5;
const int maxa=1e5+5;
int n;
int a[maxn];
int cnt[maxa];
struct Node{
int val;
int len;
}up[maxn],down[maxn];
int main(){
freopen("seq.in","r",stdin);
freopen("seq.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]);
if(a[1]>1) goto END;
up[1].val=down[1].val=up[1].len=down[1].len=1;
for(int i=2;i<=n;++i){
up[i]=up[i-1],down[i]=down[i-1];
if(++up[i].len>2) up[i].val++,up[i].len=1;
if(++down[i].len>5) down[i].val++,down[i].len=1;
if(!a[i]) continue;
if(up[i].val>a[i]) up[i].val=a[i],up[i].len=2;
if(down[i].val<a[i]) down[i].val=a[i],down[i].len=1;
if(a[i]<down[i].val||a[i]>up[i].val) goto END;
}
if(up[n].len==1){
up[n].val--;
up[n].len=5;
}
if(up[n].val<down[n].val) goto END;
a[n]=up[n].val;
printf("%d\n",a[n]);
cnt[a[n]]++;
for(int i=n-1;i>=1;--i){
if(!a[i]){
a[i]=min(up[i].val,a[i+1]);
if(cnt[a[i]]>=5) a[i]--;
}
cnt[a[i]]++;
}
for(int i=1;i<=n;++i) printf("%d ",a[i]);
return 0;
END: puts("-1"); return 0;
}