Dreamoon Likes Coloring(构造+思维题) Codeforces Round #631 (Div. 2)

在这里插入图片描述

题目大意

       给 n ( n < = 100000 ) n(n<=100000) n(n<=100000)个待染色的格子,给 m m m l i l_i li,对应 m m m次染色过程( m m m种颜色),第 i i i次染色的区间范围为 [ p i , p i + l i − 1 ] [p_i,p_i+l_i-1] [pi,pi+li1],其中, p i p_i pi的值可从区间 [ 1 , n − l i + 1 ] [1,n-l_i+1] [1,nli+1]中任选。每一个格子最终的颜色为最后一次对其染色的值,要求构造使得每一个格子都被染色且 m m m种颜色均出现的染色方案,如果不存在则输出 − 1 -1 1

分析过程

       这一道题乍一看无从下手(乍二看也是 )。首先想到一种情形,如果所有染色区间的长度之和小于 n n n的话是肯定不存在有效方案的(即 ∑ l i < n \sum l_i<n li<n,此时 n n n个格子无法被全部染色),此时直接输出 − 1 -1 1
       接下来,我们尝试每一次染色的左端点都比上一次染色向后偏移一位这种构造方式,即第 i i i次染色区间的 p i = i p_i=i pi=i,这样可以保证每一个染色区间中至少左端点不会被后面的染色区间覆盖,但是我们可以发现,如果在第 i i i次染色的时候, p i p_i pi能够取到的最大值比 i i i还小,即 n − l i + 1 < i n-l_i+1<i nli+1<i的时候,是没办法继续构造下去的,这个时候,我们注意到,如果出现这种情形必然不存在构造方案,因为此时第 i i i次染色区间的长度已经大于 n − i + 1 n-i+1 ni+1了,给前面的染色只留下了 < i − 1 <i-1 <i1个独立空位,因此前面的 i − 1 i-1 i1个染色区间中必然存在被完全覆盖的区间。所以,这个时候也是直接输出 − 1 -1 1即可。
       这时候我们继续顺着之前染色区间左端点不断 + 1 +1 +1的方式进行构造,会发现,如果每次染色都这样做,可能最后会存在一些格子没有被染色,所以在后续的染色中必然要更加大胆的扩大染色区间才可以。可以设 s u f f [ i ] suff[i] suff[i] l i l_i li的后缀和,我们考虑从后往前染色:当剩余的染色格子数目大于剩余染色的次数 i i i时, p i = s u f f [ i ] p_i=suff[i] pi=suff[i];当等于 i i i时,这个时候刚好可以每一次将左端点向左扩展一位而实现剩余全部格子的染色。即 p i = m a x ( i , n − s u f f [ i ] + 1 ) p_i=max(i, n-suff[i]+1) pi=max(i,nsuff[i]+1)

AC代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 100;
typedef long long ll;
ll l[maxn], suff[maxn], p[maxn], n, m;
int main(){
	int i, j;
	ios::sync_with_stdio(false);
	cin>>n>>m;
	for(i=1;i<=m;++i){
		cin>>l[i];
		if(l[i] > n - i + 1){ //无法保证在i之前染色的每一个区间拥有至少一个独立位置 
			cout<<-1; 
			return 0;
		}
	}
	for(i=m;i>=1;--i){
		suff[i] = suff[i+1] + l[i];
	}
	if(suff[1] < n) cout<<-1; //无法满足全部上色 
	else{
		for(ll i=1;i<=m;++i){ //更新答案 
			p[i] = max(i, n - suff[i] + 1);
		}
		for(i=1;i<m;++i) cout<<p[i]<<' ';
		cout<<p[i]<<'\n';
	} 
	return 0;
} 

点个赞再走撒~~~!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值