1. 程式人生 > 實用技巧 >【Codeforces 1329A】Dreamoon Likes Coloring

【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[n]+1,n]\) 開始寬鬆的擺(倒數第二段是\([n-l[n]-l[n-1]+1,n-l[n]]\),直到和上一個 \(p[i-1]=i-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;
}