联赛模拟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
",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;
}
原文地址:https://www.cnblogs.com/Lour688/p/13821441.html