Codeforces Round #681 (Div. 1) A. Extreme Subtraction

Extreme Subtraction

CodeForces 1442A.

题意#

你有一个序列 a,你可以进行 2 种操作:

  • 选择前 k 个数,将它们全部减 1
  • 选择后 k 个数,将它们全部减 1

k 由你自己定,并且每次操作可以不同。
问是否可以把通过若干次操作整个序列变为全是 0 的序列

本题多测,有 t 组数据
t30000n30000ai106

样例 #1#

样例输入 #1#

4
3
1 2 1
5
11 7 9 6 8
5
1 3 1 3 1
4
5 2 1 10

样例输出 #1#

YES
YES
NO
YES

SOLUTION 1#

分析#

两种操作都为区间操作,并且目标结果为让所有的数字都为 0,那么可以对原数组的差分数组进行考虑,判断是否可以使所有的数字都相等即可,即让 ai=0(1<in)。第一种操作在差分数组中的含义即 a[1] --, a[i] ++ (1<in+1),第二种操作在差分数组中的含义即 a[i] ++, a[n + 1] --。如果最终可以让ai=0(1<in),那么差分数组中所有的负数相加的绝对值一定是小于等于 a[1] 的。

代码#

点击查看代码
#include<stdio.h>
const int N = 3E4 + 10;
int T, n, a[N];
int main() {
  scanf("%d", &T);
  while (T -- ) {
    scanf("%d", &n);
    for (int i = 1; i <= n; i ++ ) scanf("%d", a + i);
    long long now = 0;
    for (int i = 2; i <= n; i ++ ) if (a[i] - a[i - 1] < 0) {
      now -= (a[i] - a[i - 1]);
    }
    puts(now <= a[1] ? "YES" : "NO");
  }
  return 0;
}

SOLUTION2#

分析#

题意可以转化为 构造一个单调不减的数组 inc 和 一个单调不增的数组 dec,使得 a[i] = inc[i] + dec[i],那么我们可以贪心的构造,inc[1] = 0, dec[1] = a[1],考虑inc[2]dec[2]:

  • dec[2] <= dec[1]
  • dec[2] + inc[2] = a[2],得出 dec[2] <= a[2]
  • inc[2] >= inc[1], 得出 dec[2] <= a[2] - inc[1]

要贪心的让 dec[2] 尽可能的大,因此取 dec[2] = min(dec[1], a[2] - inc[1]),最后判断此时是否有解即可。

代码#

点击查看代码
#include <cstdio>
#include <algorithm>

template < typename T > inline void chkmax(T &x, T y) {x = x >= y ? x : y;}
template < typename T > inline void chkmin(T &x, T y) {x = x <= y ? x : y;}
template < typename T > inline T max(T x, T y) {return x >= y ? x : y;}
template < typename T > inline T min(T x, T y) {return x <= y ? x : y;}
constexpr int N = 3E4 + 10;

int n, a[N];
int inc[N];
int dec[N];

void solve2() {
  scanf("%d", &n); //pre[0] = suf[n + 1] = 1E9;
  for (int i = 1; i <= n; i ++ ) {
    scanf("%d", a + i);
  }
  inc[1] = 0, dec[1] = a[1];
  for (int i = 2; i <= n; i ++ ) {
    dec[i] = min(dec[i - 1], a[i] - inc[i - 1]);
    inc[i] = a[i] - dec[i];
    if (inc[i] < inc[i - 1] || dec[i] > dec[i - 1] || inc[i] < 0 || dec[i] < 0) {
      return puts("NO"), void();
    }
  }

  puts("YES");
  
  /*
  如果执行将 [1, k] 的数字减去 1 这个操作,那么 a_i 执行的此时一定大于等于 a_{i+1}
  
  因此原题可以转化为 构造一个单调不减的数组inc 和 一个单调不增的数组dec

  使得 a[i] = inc[i] + dec[i]

  贪心的构造,inc[1] = 0, dec[1] = a[1]
  考虑inc[2] 和 dec[2]
  dec[2] <= dec[1]
  dec[2] + inc[2] = a[2] --> dec[2] <= a[2]
  inc[2] >= inc[1]       --> dec[2] <= a[2] - inc[1]

  贪心的让dec[2] 尽可能的大,因此取 dec[2] = min(dec[1], a[2] - inc[1])

  判断此时是否有解即可
  */
}

int main() {
  int T; scanf("%d", &T);
  while (T -- ) solve2();
  return 0;
}

SOLUTION3#

分析#

考虑每个位置 i,如果 ai>ai+1 ,那么 i 这个位置至少要执行 aiai+1 次第一种操作,此时要考虑前缀最小值是否可以执行这么多次这个操作。 如果 ai<ai+1,那么 i+1 这个位置至少要执行 ai+1ai 次第二种操作,此时要考虑后缀最小值是否可以执行这么多次这个操作。
如果都满足,则可以将整个序列变为全 0 序列。

代码#

点击查看代码
#include <bits/stdc++.h>
using namespace std;

template < typename T > inline void chkmax(T &x, T y) {x = x >= y ? x : y;}
template < typename T > inline void chkmin(T &x, T y) {x = x <= y ? x : y;}

constexpr int N = 3E4 + 10;

int n, a[N];
// int pre[N], suf[N];

void solve() {
  scanf("%d", &n); //pre[0] = suf[n + 1] = 1E9;
  for (int i = 1; i <= n; i ++ ) {
    scanf("%d", a + i);
  }
  int mi = 1E9;
  for (int i = 1; i < n; i ++ ) {
    if (a[i] > a[i + 1] && mi < a[i] - a[i + 1]) {
      return puts("NO"), void();
    }
    chkmin(mi, a[i]);
    mi -= max(0, a[i] - a[i + 1]);
  }
  reverse(a + 1, a + 1 + n);
  mi = 1E9;
  for (int i = 1; i < n; i ++ ) {
    if (a[i] > a[i + 1] && mi < a[i] - a[i + 1]) {
      return puts("NO"), void();
    }
    chkmin(mi, a[i]);
    mi -= max(0, a[i] - a[i + 1]);
  }
  puts("YES");
  
}

int main() {
  int T; scanf("%d", &T);
  while (T -- ) solve();
  return 0;
}
posted @   ccz9729  阅读(53)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示
主题色彩