cf round 613 div2 C. Dreamoon Likes Coloring(贪心)

题目链接
题目大意:给定一个长度为n的线段.现在有m次操作,每次操作可以染长度为li的线段为第i种颜色.问怎么染最后可以让全部颜色都有一块相应的区间.
显然的贪心题.问题是怎么贪合适.昨晚a了之后就睡觉了,早上起来发现悲催的hack了.后面改了一点就a了.
分享一下思路.因为最后要让每一种颜色都有,也就是说,最后只要让每一种颜色有长度至少为1的区间就够了.染的时候应该尽量空出位置来让后面的颜色能不覆盖掉前面的颜色.因为当这个颜色的左端点越靠右,那么以后的染色越有可能覆盖掉全部的前一种的颜色. 所以应该尽量的靠左染.也就是左端点1,2,3,4…这样子染色更有机会达到目的.
不过因为题目要求最后每个格子必须有颜色. 那么这样子染是很可能最后有些格子没颜色的.就需要增加判断条件. 先求出所有染色长度总和sum.我们用一个r索引表示当前左端点(最靠右的左端点也就是上次染色开始的地方)在哪里.last索引表示当前最右的端点在哪里.每次染之前先假设这次染色染r后面一个格子,先更新last.然后sum减掉当前染色长度.看剩余的长度够不够染最后面n-last的范围.如果够,我们就染r+1.不够就染n-sum-a[i]+1(这个可以在纸上面画一下来推这个式子).这就是染色的方法. 要注意的是一定要先更新last.不然的话是会被hack的(昨晚的惨痛教训).
还有一个判断无解的问题.如果sum<n无解(显然).如果染色途中出现了当前染色长度会覆盖掉上一个左端点.无解.因为我们都已经那么贪心的尽量靠左染色了.还会出现全部覆盖的问题就没法染了.
被hack的代码

#define LL long long
#define pb push_back
#define pii pair<LL,LL>
#include <bits/stdc++.h>
 
using namespace std;
 
const int N = 2e5+10;
const int mod = 9901;
 
int a[N];
int ans[N];
LL gcd(LL a,LL b){return b == 0?a:gcd(b,a%b);}
int main(){
	ios::sync_with_stdio(false);
	int n,m;
	cin >> n >> m;
	LL sum = 0;
	for(int i=1;i<=m;++i) cin >> a[i],sum += 1LL*a[i];
	if(sum < n){
		cout << -1;
		return 0;
	}
	int r = 1,last = a[1];
	ans[1] = 1;
	sum -= a[1];
	for(int i=2;i<=m;++i){
		sum -= a[i];
//		cout << sum << " " << last << endl;
		if(a[i] > n-r){
			cout << -1;
			return 0;
		}
		if(sum < n-last){
			r = n-sum-a[i]+1;
			last = n-sum;
			ans[i] = r;
		}
		else{
			r += 1;
			last = max(last,r+a[i]-1);
			ans[i] = r;
		}
	}
	for(int i=1;i<=m;++i) cout << ans[i] << " ";
	
	return 0;
}

AC的代码(唯一的区别就是last更新的方式)

#define LL long long
#define pb push_back
#define pii pair<LL,LL>
#include <bits/stdc++.h>
 
using namespace std;
 
const int N = 2e5+10;
const int mod = 9901;
 
int a[N];
int ans[N];
LL gcd(LL a,LL b){return b == 0?a:gcd(b,a%b);}
int main(){
	ios::sync_with_stdio(false);
	int n,m;
	cin >> n >> m;
	LL sum = 0;
	for(int i=1;i<=m;++i) cin >> a[i],sum += 1LL*a[i];
	if(sum < n){
		cout << -1;
		return 0;
	}
	int r = 1,last = a[1];
	ans[1] = 1;
	sum -= a[1];
	for(int i=2;i<=m;++i){
		sum -= a[i];
//		cout << sum << " " << last << endl;
		last = max(last,r+a[i]);
		if(a[i] > n-r){
			cout << -1;
			return 0;
		}
		if(sum < n-last){
			r = n-sum-a[i]+1;
			last = n-sum;
			ans[i] = r;
		}
		else{
			r += 1;
			ans[i] = r;
		}
	}
	for(int i=1;i<=m;++i) cout << ans[i] << " ";
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45590210/article/details/105306666
今日推荐