CF #631 (Div. 2) C-Dreamoon Likes Coloring

题目里面好多细节的地方没有注意到啊∑(っ°

https://codeforces.com/contest/1330/problem/C
题意:
1、给你一排长度为n的单元格,和m种颜色,还有m个数 l l l1 l l l2 l l l3 l l lm,然后给这些单元格染色;
2、染色规则:单元格的颜色由 对它的最后一次操作决定,对于第 i i i次染色操作,你可以从从区间[ 1 1 1, n n n − - l l li + + + 1 1 1]中选一个数 p p p,然后给区间[ p p p p p p + + + l l li − - 1 1 1 ]染上第 i i i种染色
3、要求:(1)按给出的颜色顺序进行m次染色后,每种颜色至少出现一次;(2)每个区间都要被着色。


思路:
1、因为两个区间段一个是 − - l l li + + + 1 1 1,一个是 + + + l l li − - 1 1 1。所以可以试着将它们合并起来: p p p = = = 1 1 1时,染色区间为[ 1 1 1, l l li ]; p p p = = = n n n − - l l li + + + 1 1 1时,染色区间为[ n n n − - l l li + + + 1 1 1, n n n]。所以染色区间段就是n上,任意一个长度为 l l li的连续子区间。

2、因为它是按顺序染色的,所以:第一种染色肯定是从第一个单元格开始, p p p[1]=1;最后一种颜色肯定是从 n n n − - l l lm + + + 1 1 1开始(即,会占据后 l l lm个单元格), p p p[m]= n n n − - l l lm + + + 1 1 1。从最后一种颜色开始处理,然后每种颜色占据 l l l[i]的单元格(为了保证能填满n个单元格),直到第i个元素满足i+ l l l[i]>= p p p[i+1]时,之后每种颜色均只占一个单元格,即 p p p[i]=i(保证每种颜色至少出现一次)。
注意: 处理 p p p[i]时,要保证p[i] < < < n n n − - l l li + + + 1 1 1(即区间左端点最大值)


//开始说废话了,做题心路历程:( 1、体会到数据范围的重要性,开始没有认真看pi的范围,都不知道染色所选的区间可不可以超过n的范围;2、写代码写着写着就忘了是按照给的顺序染色,最后排除第一点漏洞后,写了一个可以尽量得到染色方案的代码(不按顺序染色),以为可以过了,然后h……h……h……h……:
在这里插入图片描述
3、考虑到上面注意事项对答案选择的影响,又想到前面如此肯定地选择 l l l[i]长度的染色区间,会不会使本来有解的情况变成无解,因为之前本来可以留下更多的空单元格。但是后来仔细想了一下:如果后面因为注意事项的影响导致没有足够的空单元格分给后面每一种颜色,此时就算前面多留一些空单元格,结果仍是如此,当前单元格只能选择 n n n − - l l li + + + 1 1 1为起点。

代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#include <vector>
//#define int long long
using namespace std;
const int INF=0x3f3f3f3f;
const int manx=1e5+10;
int pos[manx],a[manx];
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        scanf("%d",&a[i]);
    pos[m]=n-a[m]+1;
    int flag=0;
    for(int i=m-1;i>=1;i--)
    {
        if(i>=pos[i+1])//已经填充到pos[i+1]的位置了,只剩下<i个空单元格,但前面还有i中颜色
        {
            printf("-1\n");
            return 0;
        }
        if(flag)
        {
            if(i>n-a[i]+1)//同上一条注释
            {
                printf("-1\n");
                return 0;
            }
            pos[i]=i;
            continue;
        }
        if(i+a[i]>=pos[i+1])
        {
            flag=1;
            pos[i]=min(n-a[i]+1,i);//考虑到注意事项,两者之间取最小
        }
        else pos[i]=pos[i+1]-a[i];
    }
    if(pos[1]!=1)//也就是它大于1了,就是说n个单元格不能填满
    {
        printf("-1\n");
        return 0;
    }
    for(int i=1;i<=m;i++)
        printf("%d%c",pos[i],i==n?'\n':' ');
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值