CF-Round #631-div2-C题&div1-A

CF-Round #631-div2-C题&div1-A

C. Dreamoon Likes Coloring

传送门

这道题也是div1的A题。

这道题是一道贪心题。
这道题我写了很久。第一题目不能理解,第二贪心策略理解不到位。
最后理解之后的那一刻就真的拍桌子欢呼了。。(没有夸张)

题目是一个涂色。给了你m种颜色。要求m种颜色在最后效果中必须出现并且没有未涂色的格子。
然后给出涂色的一个特定区间l[]。
让你构造一个序列q[]满足上述要求。
每次涂色需要涂区间q[i] ~ q[i] + l[i] - 1的部分;最终格子的颜色以最后涂上的颜色为准。

就是那个给定的区间那里我就很迷。。特别是范围部分。。。真的迷。要求q[i] + l[i] - 1不能大于n了。
也就是说q[i]本来就是有范围要求的了。

两种情况很明显需要特判不满足要求的:
1.如果l[]的总和sum都小于n的话,说明就算我们分散的涂颜色。但最后还是有格子没有涂上,不能涂满所有的格子。
第二个特判后面再说。

很显然,我们构造出来的第一个p[1] = 1;(肯定要从第一个格子开始啦)
并且为了不让后面涂色的区间完全覆盖前面涂色的区间:我们有:
p[i + 1] > p[i];这个也很明显把。
比如p[2] > p[1] = 1;也就是说p[2] >= 2;
p[3] > p[2] >= 2; p[3] >= 3;
所以我们可以得到p[i] >= i; 就是需要不小于当前的下标。

再来说一下第二种特判情况:

我们根据上面可以得到p[i] >= i;
不妨让p[i]取最小值i;
那么当前涂色区间为:i + l[i] - 1;
那么如果i + l[i] - 1 > n的话(最小值都大于n了)肯定没有满足要求的序列了。输出-1即可。

贪心策略:尽可能让前面的涂色区域小,给后面的涂色区域留更大的空间。
再看求p[m]的时候。我们既要求不能让p[m] + l[m] - 1不能超过n,也不能让p[m] + l[m] - 1 小于n(因为按照前面说的贪心策略)。所以只能让p[m] + l[m] - 1 = n;
我们得到式子p[m] = n - l[m] + 1;

再考虑:要使得没有空格子,也就是每个格子都需要涂上颜色。
考虑p[i]和p[i + 1]的关系。
当涂到第i种颜色时区域:p[i] ~ p[i] + l[i] - 1;
所以p[i + 1]最大应该都是p[i] + l[i](这种恰好跟上一个颜色衔接的情况)
所以我们得到另外一个式子:
p[i + 1] <= p[i] + l[i];
移项得:
p[i] >= p[i + 1] - l[i];
通过这个式子我们枚举一下:
p[i] >= p[i + 1] - l[i];
p[i + 1] >= p[i + 2] - l[i + 1];
p[i + 2] >= p[i + 3] - l[i + 2];



p[m-1] >= p[m] - l[m - 1];
我们把不等式左边的相加,不等式右边的相加。消项;
得到:
p[i] >= p[m] - l[i] - l[i + 1] - l[i + 2] - l[m - 1];
我们再把上面得到的式子p[m] = n - l[m] + 1代入上式:
得到p[i] >= n - suf[i] + 1;其中suf[i]表示i的后缀和。
然后还有上面得到的式子p[i] >= i;
两个式子都要满足。我们取一下最大值就行。我们的贪心策略是尽可能取小嘛。所以
p[i] = max(i, n - suf[i] + 1);
维护一下~

完成啦~(开心)

理解了之后就很好解决了,主要是特判的情况要考虑到位。
最后要开ll,不然会wa.

代码部分:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;

ll n, m;
ll l[N];
int flag;
ll sum;
ll suf[N];

int main()
{
	cin >> n >> m;
	for (ll i = 1; i <= m; i++)
	{
		cin >> l[i];
		sum += l[i];
		if (l[i] + i - 1 > n)
		{
			flag = 1;
		}
	}
	if (flag || sum < n)
	{
		cout << "-1\n";
	}
	else
	{
		suf[m] = l[m];
		for (ll i = m - 1; i >= 1; i--)
		{
			suf[i] = suf[i + 1] + l[i];
		}
		for (ll i = 1; i <= m; i++)
		{
			cout << max(i, n - suf[i] + 1) << " ";
		}
		cout << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

娃娃酱斯密酱

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值