Codeforces Round #681 (Div. 1, based on VK Cup 2019-2020 - Final)
原创
©著作权归作者所有:来自51CTO博客作者wx63db9cf49ed95的原创作品,请联系作者获取转载授权,否则将追究法律责任
A. Extreme Subtraction
题意:
给你一个长度为
序列,你可以进行无数次操作,让前
个数减一或让后
个数减一,
,问是否能把这整个序列变为 
可以这样考虑,把这个序列从从后往前处理,若后一个数大于前一个数,则让后面的所有数减少到等于前一个数字,若能实现操作就是
.
例如:
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
对于前面比后面大的那些肯定可以构成,剩下的序列就全部可以靠第一个数来减去。
这个是判断出现后面比前面数大的求差值和和最后一个数的大小关系,记为

还有一种,
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
变成递增的。
这个是判断出现后面比前面数小的求差值和和最后一个数的大小关系,记为

所以只要满足 
进一步推导如果两个数两个都大的话肯定就是
了所以
等价于
,也就是可以写成 
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
题意:
每个数的那一轮一定是删除其左边或右边的数(数满足轮次小于当前数的轮次)。
删除其旁边的数后,相当于把当前数补位到其旁边的数,后面的数依然可以删除其旁边的数。
枚举每个轮次选中的数,
然后看其两侧是否可选,若都可选,说明当前轮次
个选择,若一个可选,说明当前轮次
个选择。若无可选,说明无法构造出结果直接输出 
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;
}