题目链接

链接

翻译

让你按顺序对连续的点进行染色(总共有 \(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;
}