CF1442A - Extreme Subtraction
题意 :
可以将数组一定长度的前缀全部减一,或者一定长度的后缀全部减一,问是否能将整个数组全减成0
1800分的题,div2D题,div1A题
还是做很久,而且还卡,绝了
经典 : 为什么题解代码这么短
两种做法
差分:
感觉特别妙,看到差分回去又看了好久, 然后硬是没看出来,还是看了题解
将整个数组全为0转化成差分数组全为0
这里原数组为a[],差分数组为b[]
将前缀一段(长度为len)全部减一的操作就变成b[1] + 1,b[len + 1] - 1
将后缀一段(长度为len)全部减一的操作就变成b[n - len + 1] + 1 , b[n + 1] - 1
于是可以考虑差分数组中所有小于0的数的绝对值和是否小于b[1]
#include <bits/stdc++.h>
using namespace std;
const int maxn = 30010;
int a[maxn];
int b[maxn];
inline void insert(int l, int r, int c) {
b[l] += c;
b[r + 1] -= c;
}
inline void init(int n) {
for(int i = 0; i < n + 10; ++ i) {
b[i] = 0;
}
}
int main() {
int T;
cin >> T;
while(T --) {
int n;
cin >> n;
init(n);
for(int i = 1; i <= n; ++ i) {
cin >> a[i];
insert(i, i, a[i]);
}
int sum = 0;
for(int i = 1; i <= n; ++ i) {
if(b[i] < 0) sum -= b[i];
}
if(sum <= b[1]) cout << "YES\n";
else cout << "NO\n";
}
return 0;
}
构造, 贪心 :
我也贪了好久,但是是乱贪,我服了,为什么会有人贪心都不会贪
刷 题 太 少 : )
从一个方向开始扫,每扫到一个比它大的数,就意味着我们需要动用另一个方向的操作把它减小(至少减到恰好相等)。当另一个方向不能将它减到合适,即出现为了把它减到合适不得不把其它无辜的数减到小于 0 的情形,答案就是 No 。假如我们成功的做到了这一点,我们不难发现,此时我们已经构造出了扫的方向上的不递增数列。答案自然是 Yes 。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 30010;
int a[maxn];
int main() {
int T;
cin >> T;
while(T --) {
int n;
cin >> n;
for(int i = 1; i <= n; ++ i) {
cin >> a[i];
}
int d = 0, mn = a[1];
bool f = 0;
for(int i = 1; i <= n; ++ i){
a[i] -= d;
if(a[i] < 0) {
f = 1;
break;
}
if(mn > a[i]) {
mn = a[i];
}
else {
d += a[i] - mn;
}
}
if(f) cout << "NO\n";
else cout << "YES\n";
}
return 0;
}