zoukankan      html  css  js  c++  java
  • 简单的填数「贪心」

    题目描述

    题库后缀为contest/138/problem/3

    思路分析

    我太爱贪心题了,我上辈子一定是道贪心题

    • 题意是要求的序列是每个数都只能和前面的数相等,或者比前面的数大 (1),且每个数最少出现 (2) 次,最多出现 (5) 次。
    • 将所有不是 (0) 的数放进一个结构体里,两两之间填数,考虑如何填可以即合法,又能保证答案最优
    • 对于两个非零数之间,我们填数的大小范围就是这两个数之内,可以包括这两个数,为了使答案最优,我们每一次填够两个,如果下个数不超过可填的数的范围就去填下一个,否则接着填这个数。但这时候如果遇到两个数之间有很多零,很有可能会出现一个数被填的超过了 (5) 次的情况,所以需要对前面的数修改。类似于,记录每个数第一次和最后一次出现的位置,就可以快速修改,如果需要修改的数已经出现了 (5) 次,就让前面的前面数也改,这样递归下去,最后让原来需要修改的可以修改。
    • 最后按题目要求 check 一下就好了
    • 还有挺多细节的,就不一一细说了

    (Code)

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define R register
    #define N 200010
    using namespace std;
    inline int read(){
    	int x = 0,f = 1;
    	char ch = getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	return x*f;
    }
    int n,b[N],cnt[N],tot;
    int begin[N],end[N];
    bool flag[N];
    struct data{
    	int num,pos;
    }a[N];
    void rechoose(int x){//修改
    	//puts("???");
    	if(x==0)return;
    	if(cnt[x]<5){//直接改
    		if(!flag[end[x]+1]){
    			end[x]++;
    			begin[x+1]++;
    			b[end[x]]--;
    			cnt[x]++,cnt[x+1]--;
    		}
    		return;
    	}
    	else {//递归处理,让x可以修改
    		rechoose(x-1);
    		if(cnt[x]<5){
    			if(!flag[end[x]+1]){
    				end[x]++;
    				begin[x+1]++;
    				b[end[x]]--;
    				cnt[x]++,cnt[x+1]--;
    			}
    			return;
    		}
    	}
    }
    void get_num(int l,int r,int mn,int mx){//填数
    	b[l] = mn,b[r] = mx;
    	int now = mn;
    	for(R int i = l+1;i < r;i++){
    		if(cnt[now]>=2&&now<mx){
    			if(r==n+1&&n-i+1<2){//这里特判一下,否则会出现1 2 2 3这种情况
    				cnt[now]++;
    				b[i] = now;
    				if(cnt[now]>5)rechoose(now-1);
    				continue;
    			}
    			end[now] = i-1;
    			now++;
    			cnt[now]++;
    			begin[now] = i;
    			b[i] = now;
    			continue;
    		}
    		cnt[now]++;
    		b[i] = now;
    		if(cnt[now]>5)rechoose(now-1);
    	}
    	if(r==n+1)return;
    	cnt[b[r]]++;
    	if(cnt[b[r]]>5)rechoose(b[r]-1);
    	if(now==mx-1)begin[mx] = r;
    }
    bool check(){
    	int now = 0,cnt = 0;
    	for(R int i = 1;i <= n;i++){
    		if(b[i]<now)return 0;
    		if(b[i]>now){
    			if(b[i]-now>1)return 0;
    			if(now&&cnt<2)return 0;
    			cnt = 1,now = b[i];
    		}
    		else cnt++;
    		if(cnt>5)return 0;
    	}
    	if(cnt<2)return 0;
    	return 1;
    }
    int main(){
    	freopen("seq.in","r",stdin);
    	freopen("seq.out","w",stdout);
    	n = read();
    	a[++tot].num = 1,a[tot].pos = 0;//把起止点也加进去,否则开头和末尾的零是没有填的
    	for(R int i = 1;i <= n;i++){
    		int x = read();
    		if(x)a[++tot].num = x,a[tot].pos = i,flag[a[tot].pos]=1;
    	}
    	a[++tot].num = 0x3f3f3f3f,a[tot].pos = n+1;
    	for(R int i = 2;i <= tot;i++){
    		get_num(a[i-1].pos,a[i].pos,a[i-1].num,a[i].num);
    	}	
    	if(!check())puts("-1");
    	else{
    		printf("%d
    ",b[n]);
    		for(R int i = 1;i <= n;i++)printf("%d ",b[i]);
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    [原] KVM 虚拟化原理探究(6)— 块设备IO虚拟化
    [原] KVM 虚拟化原理探究(5)— 网络IO虚拟化
    [原] KVM 虚拟化原理探究(4)— 内存虚拟化
    [原] KVM 虚拟化原理探究(3)— CPU 虚拟化
    [原] KVM 虚拟化原理探究(2)— QEMU启动过程
    [原] KVM虚拟机网络闪断分析
    [原] KVM 环境下MySQL性能对比
    [源]云计算技术堆栈系列——鸟瞰
    [原] 利用 OVS 建立 VxLAN 虚拟网络实验
    [原] Cgroup CPU, Blkio 测试
  • 原文地址:https://www.cnblogs.com/hhhhalo/p/13820725.html
Copyright © 2011-2022 走看看