【Codeforces 1329A】Dreamoon Likes Coloring

题目链接

链接

翻译

让你按顺序对连续的点进行染色(总共有 (m) 个连续块需要染色)

你可以指定这个连续块的区间,但是长度必须是 (li) (但不能超过边界)

然后后面的染色会覆盖前面的染色,且每个连续块的染色(要染的颜色)都不一样。

要求 (m) 次染色过后,所有 (m) 种颜色都至少还存在一个位置。且每个点(1-n)都至少被染色过一次。

题解

两种情况:

(1) 种,所有的 (l) 的值加起来还不到 (n),那么无论怎么染色都有点没染到。无解

(2) 种,考虑最紧凑的染色方法,即第 (i) 次染色的位置 (p[i] = p[i-1] + 1)(p[1]=1) 也即 (p[i]=i),这样只会留一个上次染色的颜色在位置 (i-1),这是最紧凑的情况了。

对于这种紧凑的染色方法,如果某个位置还有 (i+l[i]-1>n) 这就说明第 (i) 种颜色无论怎么染,都会让前面的某些颜色消失。所以无解。

我们考虑这两种情况,其实就对应了宽松和紧凑两种染色方法,宽松也即所有的染色连续块都不相交。紧凑也即连续两个染色块非常紧凑地连在一起。

那我们直接用第二种方法不就行了?

但是有一个问题,就是只用第二种方法的话,可能会出现在后面某些位置没有染上色的情况,所以得宽松和紧凑两种方法结合使用。

开始的时候后面所有的 (l[i]) 的值加上当前位置比 (n) 大(宽松摆就会超过 (n) 了),那没关系,我们就按照紧凑的方法摆,也即 (p[i]=i)

一旦某个时刻后面所有的 (l[i]) 的值加上当前位置比 (n) 小了,或者等于了。这说明,再这样紧凑着摆的话,就不够 (n) 个格子都染上色了。

则我们从最后一段 ([n-l[m]+1,n]) 开始宽松的染色(倒数第二段是([n-l[m]-l[m-1]+1,n-l[m]]),直到和上一个 (p[i-1]=i-1) 的紧凑染色覆盖的区域有交集为止。
(真正输出的时候,对于第 (i) 次需要开始紧凑染色的位置,就直接输出(n-∑_{k=i}^ml_k)+1就好,对应了这种逆着宽松染色的过程)

代码1

#include <bits/stdc++.h>
#define LL long long
using namespace std;
 
const int N = 1e5;
 
int n, m;
int l[N + 10];
 
int main(){
    scanf("%d%d",&n,&m);
    LL rest = 0;
    for (int i = 1;i <= m; i++){
        scanf("%d",&l[i]);
        rest += l[i];
    }
    if (rest < n){
        puts("-1");
        return 0;
    }
    for (int i = 1;i <= m; i++){
        if (i + l[i] - 1 > n){
            puts("-1");
            return 0;
        }
    }
    for (int i = 1;i <= m; i++){
        if (i + rest - 1 > n){
            printf("%d",i);
        }else{
            printf("%d",n - rest + 1);
        }
        if (i == m){
            puts("");
        }else{
            putchar(' ');
        }
        rest -= l[i];
    }
    return 0;
}
原文地址:https://www.cnblogs.com/AWCXV/p/14110401.html