A. 3778. 平衡数组

题目链接:​​https://www.acwing.com/problem/content/3781/​

题目大意:\(m\) 次题目要求的操作使最终所有数都相等。

解题思路:思维题。将所有元素加上 \(i\) 等价于将这个数减去 \(i\)。所以一种必定可行的方案就是一次操作第 \(2, 3, \ldots, n\)。

示例程序:

#include <bits/stdc++.h>
using namespace std;

int T, n;

int main() {
cin >> T;
while (T--) {
cin >> n;
cout << n-1 << endl;
for (int i = 2; i <= n; i++) {
if (i > 2) cout << " ";
cout << i;
}
cout << endl;
}
return 0;
}

B. 3779. 相等的和

题目链接:​​https://www.acwing.com/problem/content/3782/​

题目大意:略。

解题思路:枚举。先求出每个序列的和,设第 \(i\) 个数列的元素和为 \(sum_i\),然后对于 第 \(i\) 个数列中的数值为 \(x\) 的元素,删除 \(x\) 后数列中剩余元素和为 \(sum_i - x\),判断 \(sum_i - x\) 在别的数列中是否存在(用 map),如果如在一个 \(sum_j - y = sum_i - x\),则答案就找到了。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;
int k, n, a[maxn];
map<int, pair<int, int>> mp;

int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> k;
for (int i = 1; i <= k; i++) {
cin >> n;
int sum = 0;
for (int j = 1; j <= n; j++) {
cin >> a[j];
sum += a[j];
}
for (int j = 1; j <= n; j++) {
if (mp.find(sum - a[j]) != mp.end()) {
pair<int, int> v = mp[sum - a[j]];
if (v.first != i) {
cout << "YES" << endl;
cout << v.first << " " << v.second << endl;
cout << i << " " << j << endl;
return 0;
}
}
else
mp[sum - a[j]] = {i, j};
}
}
cout << "NO" << endl;
return 0;
}

题目链接:

题目大意:

解题思路:(下面说的递增/递减指的都是非严格单调递增/递减)

考虑到最终的数列只有如下三种情况:

  1. 全部递增;
  2. 全部递减;
  3. 先递增再递减。

所以可以定义状态 \(f_{1,i}\) 表示区间 \([1,i]\) 递增的情况下的最大和,\(f_{2,i}\) 表示区间 \([i,n]\) 递减的情况下的最大和,则答案为 \(\max\{ f_{1,i} + f_{2,i+1} \}\)

实现时可以使用 单调队列 优化。

示例程序:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e5 + 5;
int n;
long long a[maxn], f1[maxn], f2[maxn];
deque<int> que;

int main() {
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
// 先从前往后求 f1[i]
for (int i = 1; i <= n; i++) {
while (!que.empty() && a[que.back()] > a[i]) que.pop_back();
int p = que.empty() ? 0 : que.back();
f1[i] = f1[p] + (i - p) * a[i];
que.push_back(i);
}
// 再从后往前求 f2[i]
que.clear();
for (int i = n; i >= 1; i--) {
while (!que.empty() && a[que.back()] > a[i]) que.pop_back();
int p = que.empty() ? (n+1) : que.back();
f2[i] = f2[p] + (p - i) * a[i];
que.push_back(i);
}
int x = 1; // 最大值下标
for (int i = 2; i <= n; i++)
if (f1[i] + f2[i] - a[i] > f1[x] + f2[x] - a[x])
x = i;
long long y = a[x];
for (int i = x-1; i >= 1; i--) y = a[i] = min(y, a[i]);
y = a[x];
for (int i = x+1; i <= n; i++) y = a[i] = min(y, a[i]);
for (int i = 1; i <= n; i++) {
if (i > 1) cout << " ";
cout << a[i];
}
cout << endl;
return 0;
}