CF-Codeforces Round #210 (Div. 1)-A-Levko and Array Recovery

ACM模版

描述

描述

题解

像我这样的渣渣,怎么可能有 Div.1 的门票,完全是一个网友找我帮他参谋这道题,才有机会看 Div.1,这是一道有坑的问题,还好被我瞎猫逮着死耗子,碰对了。

英文题,最让我头疼,还好网友给我大致翻译了一下,我第一结论,这是个逆向思维的问题,需要反推,但是,随后我就陷入了死胡同,怎么推啊?想来想去,还好我不是意志坚定的人,我放弃了逆向思维,想到了一个正向收缩区间的思路,给 a[i] 初始化一个特别大的区间,然后正向推,不断收缩区间,最后在区间内输出一组解后即可,但是后来发现,首先我想着区间就有问题,因为这里有的需要满足最大值等于 d,那么区间内的数就不是随便取的就可以满足最后结果,那么我们求区间的意义何在呢?这里的操作除了加法外,只让求最大值,那么我想,这里我们完全可以忽略下界,只考虑上界,初始化 a[i] 一个无穷大的数作为上界,然后不断收缩上界,最后我们只需要把得到的 a 数组作为结果正向执行操作检验一次即可判断是否为 NO。可是这时我却 WA ON 3,挂在了第三组,陷入了一个数据范围的坑,我设置的 INF 为 0x3f3f3f3f,大于题目要求的 10^9,所以对于有些特殊的数据,比如说第三组,存在某一个(或多个)位置的数没有对 m 次操作产生大的影响,所以最后仍然为 INF,那么就不符合题意了,自然 WA,所以呢,最后统一进行一下判断是否为 INF 即可 AC 之。

我想,这个够详细了吧……虽然废话占了一大半。

代码

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

const int MAXN = 5e4 + 10;
const int INF = 0x3f3f3f3f;

int n, m;
int a[MAXN], cnt[MAXN];
int op[MAXN], l[MAXN], r[MAXN], d[MAXN];

int main()
{
    memset(a, 0x3f, sizeof(a));
    memset(cnt, 0, sizeof(cnt));
    cin >> n >> m;

    for (int i = 0; i < m; i++)
    {
        scanf("%d%d%d%d", op + i, l + i, r + i, d + i);

        if (op[i] == 1)
        {
            for (int j = l[i]; j <= r[i]; j++)
            {
                cnt[j] += d[i];
            }
        }
        else
        {
            for (int j = l[i]; j <= r[i]; j++)
            {
                a[j] = min(a[j], d[i] - cnt[j]);
            }
        }
    }

    for (int i = 1; i <= n; i++)
    {
        if (a[i] == INF)
        {
            cnt[i] = a[i] = 0;
        }
        else
        {
            cnt[i] = a[i];
        }
    }
    for (int i = 0; i < m; i++)
    {
        if (op[i] == 1)
        {
            for (int j = l[i]; j <= r[i]; j++)
            {
                cnt[j] += d[i];
            }
        }
        else
        {
            int MAX_ = -INF;
            for (int j = l[i]; j <= r[i]; j++)
            {
                MAX_ = max(MAX_, cnt[j]);
            }
            if (MAX_ != d[i])
            {
                printf("NO\n");
                return 0;
            }
        }
    }

    printf("YES\n");
    for (int i = 1; i < n; i++)
    {
        printf("%d ", a[i]);
    }
    printf("%d\n", a[n]);

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值