Codeforces Round #681 (Div. 1, based on VK Cup 2019-2020 - Final)

A. Extreme Subtraction

题意:

给你一个长度为 n n n 序列,你可以进行无数次操作,让前 k k k个数减一或让后 k k k 个数减一, 1 < = k < = n 1<=k<=n 1<=k<=n ,问是否能把这整个序列变为 0 0 0 序列,其实最多的操作次数就是第一个数加上最后一个数。

可以这样考虑,把这个序列从从后往前处理,若后一个数大于前一个数,则让后面的所有数减少到等于前一个数字,若能实现操作就是 Y E S YES YES.

例如:

4 5 6 4 5 6 4 8 9

4 5 6 4 5 6 4 4 4

4 5 6 4 4 4 2 2 2

4 4 4 2 2 2 0 0 0

对于前面比后面大的那些肯定可以构成,剩下的序列就全部可以靠第一个数来减去。
这个是判断出现后面比前面数大的求差值和和最后一个数的大小关系,记为

n u m 2 < = a [ n ] num2 <= a[n] num2<=a[n]

还有一种,

4 5 6 4 5 6 4 8 9

2 3 4 4 5 6 4 8 9

0 1 2 2 3 4 4 8 9

变成递增的。

这个是判断出现后面比前面数小的求差值和和最后一个数的大小关系,记为

n u m 1 < = a [ 1 ] num1 <= a[1] num1<=a[1]

所以只要满足 n u m 1 < = a [ 1 ] ∣ ∣ n u m 2 < = a [ n ] num1 <= a[1]||num2 <= a[n] num1<=a[1]num2<=a[n] 即可。

进一步推导如果两个数两个都大的话肯定就是 a + b > c + d a+b>c+d a+b>c+d 了所以 a + b < c + d a+b<c+d a+b<c+d 等价于 a < c ∣ ∣ b < d a<c||b<d a<cb<d,也就是可以写成 n u m 1 + n u m 2 < = a [ 1 ] + a [ n ] num1 +num2<= a[1]+ a[n] num1+num2<=a[1]+a[n]

AC代码:

1:

int n;
        cin >> n;
        vector<int> a(n);
        for (int &i : a)
            cin >> i;
        int num1 = 0, num2 = 0;
        for (int i = 0; i < n-1; ++i)
        {
            if (a[i] <= a[i + 1])
                num2 += a[i + 1] - a[i];
            else
                num1 += a[i] - a[i + 1];
        }
        if (num1 <= a[0] || num2 <= a[n - 1])
            puts("YES");
        else
            puts("NO");

2:

int n;
        cin >> n;
        vector<int> a(n);
        for (int &i : a)
            cin >> i;
        int num = 0;
        for (int i = 0; i < n - 1; ++i)
            num += abs(a[i + 1] - a[i]);
        if (num <= a[0] + a[n - 1])
            puts("YES");
        else
            puts("NO");

B. Identify the Operations

题意:

每个数的那一轮一定是删除其左边或右边的数(数满足轮次小于当前数的轮次)。

删除其旁边的数后,相当于把当前数补位到其旁边的数,后面的数依然可以删除其旁边的数。

枚举每个轮次选中的数,

然后看其两侧是否可选,若都可选,说明当前轮次 2 2 2 个选择,若一个可选,说明当前轮次 1 1 1 个选择。若无可选,说明无法构造出结果直接输出 0 0 0 即可。

AC代码:
const int N = 2e5 + 50;
const ll mod = 998244353;
int a[N], b[N], pos[N], vis[N];
int n, k;

int main()
{
    int t;
    sd(t);
    while (t--)
    {
        sdd(n, k);
        rep(i, 1, n)
        {
            pos[i] = 0;
            vis[i] = 0;
        }
        rep(i, 1, n)
        {
            sd(a[i]);
            pos[a[i]] = i;
        }
        vis[0] = vis[n + 1] = n + 7;
        rep(i, 1, k)
        {
            sd(b[i]);
            vis[pos[b[i]]] = i;
        }
        ll ans = 1;
        rep(i, 1, k)
        {
            int id = pos[b[i]];
            int now = 0;
            if (vis[id + 1] <= vis[id])
                now++;
            if (vis[id - 1] <= vis[id])
                now++;
            ans = ans * now % mod;
        }
        pld(ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值