codeforce刷题(二)

CodeForces 1329A Dreamoon Likes Coloring

题意

$n$个格子,$m$次操作,第$i$次操作使用第$i$种颜色连续的染$l_i$个格子,求给出任意一种方案,使得:

  • 每个格子都被染上色
  • 每种颜色都要出现,既不能存在一种颜色被完全覆盖

题解

显然,如果 \(\sum_{i = 1}^{m}l_i < n\),则不存在这样的方案。 假如第$i$种颜色就从第$i$个格子开始染色,有两种情况可能出现

  • 如果有 \(i + l[i] - 1 > n\),则不存在满足条件的方案,因为要染第$i$种颜色,且不超出$n$个格子的方案,只有覆盖掉$i$前面的颜色,所以不满足条件2:不会有颜色被完全覆盖
  • 没有 \(i + l[i] - 1 > n\),说明$m$次操作没有染完全部的格子或者刚好染完全部的格子。从后向前考虑,第$m$次操作在第 \(n - l[m] + 1\) 格子处开始染色, 第$m - 1$次操作在第 \(n - l[m] - l[m - 1] + 1\) 格子处开始染色,第$m - 2$次操作在第 \(n - l[m] - l[m - 1] - l[m - 2] + 1\) 格子处开始染色,依次递推。在递推的过程中,判断上一种颜色染的区域的末尾是不是超过了当前颜色的染色开始位置。举例来说:如果 \((m - 1) + l[m - 1] >= n - l[m] + 1\),说明所有的格子都被染色,且每种颜色都会出现。

注意是按顺序操作 ,所以不能排序。同时,这也是为什么出现 \(i + l[i] - 1 > n\) 就代表着$i$前面的颜色会被完全覆盖。非常妙的思想:先紧凑染色,然后从后向前考虑,将染色的区域向后移动,起到补偿的作用。动画演示

int main()
{
    cin >> n >> m;

    long long sum = 0;
    for (int i = 1; i <= m; ++i) {
        cin >> l[i];
        sum += l[i];
        ans[i] = i;
        
        if (i + l[i] - 1 > n) {
            puts("-1");
            return 0;
        }
    }

    if (sum < n) {
        puts("-1");
        return 0;
    }

    
    for (int i = m; i >= 1; --i) {
        ans[i] = n - l[i] + 1;
        n = n - l[i];
        if (i - 1 + l[i - 1] >= ans[i]) {
            break;
        }

    }

    for (int i = 1; i <= m; ++i) cout << ans[i] << " ";
    cout << endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zgglj-com/p/12659893.html