Replace With Product—CF1872G
给定一个由 n n n个正整数组成的数组 a a a。你需要仅执行以下操作一次:
例如,如果对数组 [ 5 , 4 , 3 , 2 , 1 ] [5, 4, 3, 2, 1] [5,4,3,2,1]应用参数 l = 2 , r = 4 l = 2, r = 4 l=2,r=4的操作,数组将变为 [ 5 , 24 , 1 ] [5, 24, 1] [5,24,1]。
你的任务是在应用该操作后使数组的总和最大化。找到应用该操作的最佳子数组。
输入
每个测试包含多个测试用例。第一行包含一个整数 t t t( 1 ≤ t ≤ 1 0 4 1 \le t \le 10^4 1≤t≤104)——测试用例的数量。接下来是测试用例的描述。
每个测试用例的第一行包含一个整数 n n n( 1 ≤ n ≤ 2 ⋅ 1 0 5 1 \le n \le 2 \cdot 10^5 1≤n≤2⋅105)——数组 a a a的长度。
每个测试用例的第二行包含 n n n个整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,…,an( 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1≤ai≤109)。
保证所有测试用例的 n n n的值的总和不超过 2 ⋅ 1 0 5 2 \cdot 10^5 2⋅105。
输出
对于每个测试用例,输出 2 2 2个整数 l l l和 r r r( 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1≤l≤r≤n)——用于替换乘积的子数组的边界。
如果有多个解决方案,则输出其中任何一个。
注意
在第一个测试用例中,应用参数 l = 2 , r = 4 l = 2, r = 4 l=2,r=4的操作后,数组 [ 1 , 3 , 1 , 3 ] [1, 3, 1, 3] [1,3,1,3]变为 [ 1 , 9 ] [1, 9] [1,9],总和为 10 10 10。很容易看出,通过将任何其他段替换为乘积,总和将小于 10 10 10。
在第二个测试用例中,应用参数 l = 3 , r = 4 l = 3, r = 4 l=3,r=4的操作后,数组 [ 1 , 1 , 2 , 3 ] [1, 1, 2, 3] [1,1,2,3]变为 [ 1 , 1 , 6 ] [1, 1, 6] [1,1,6],总和为 8 8 8。很容易看出,通过将任何其他段替换为乘积,总和将小于 8 8 8。
在第三个测试用例中,最佳选择是选择 l = r l = r l=r的任何操作,那么数组的总和将保持为 5 5 5,而应用任何其他操作,数组的总和将减少。
C o d e Code Code
#include
#define int long long
#define sz(a) ((int)a.size())
using namespace std;
using PII = pair<int, int>;
using i128 = __int128;
const int N = 2e5 + 10;
int n;
int a[N];
void solve() {
cin >> n;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
}
// 先去除两边的1
int l = 1, r = n;
while (l + 1 <= n && a[l] == 1) {
l ++;
}
while (r - 1 >= 1 && a[r] == 1) {
r --;
}
// 判断元素的累乘是否大于4e14,如果大于,就直接输出[l, r]
int ji = 1;
for (int i = l; i <= r; i ++) {
if (1.0 * ji * a[i] > 4e14) {
/*
由题意知,数组n个元素的和不会超过4e14
所以,当[l, r]内元素的累乘达到2e14的时候,
我们就可以确定需要对[l, r]段的元素替换为它们的
累乘。
证明:
假设正确的方法是对[ll, rr]段的元素替换为它们的
累乘(l <= ll <= rr <= r),那么增加的大小为:
i ∈ [l, ll - 1] ∪ [rr + 1, r]内的元素之和,
而减小的大小则至少为:4e14 / 2 >= 2e14,
综合来说,则是变小的。
证毕。
*/
cout << l << ' ' << r << "\n";
return;
}
ji *= a[i];
}
/*
暴力枚举。
因为已经确定a数组的累乘不会超过4e14,
即使其中 > 1 的数字都是2,数量也一定小于64个,
所以这个暴力虽然是O(n^2)的,但实际上消耗的时间很少
*/
vector <int> sum(n + 1, 0); // 累加
vector <int> prod(n + 1, 0); // 累乘
prod[0] = 1;
vector <int> one; // 记录元素值为1的下标
one.push_back(0);
for (int i = 1; i <= n; i ++) {
sum[i] = sum[i - 1] + a[i];
prod[i] = prod[i - 1] * a[i];
if (a[i] > 1) {
one.push_back(i);
}
}
int L = 1, R = 1, maxn = -1;
for (int i = 1; i <= sz(one) - 1; i ++) {
for (int j = i; j <= sz(one) - 1; j ++) {
int pi = one[i], pj = one[j];
// 把[pi, pj]区间内的所有数字换成一个数:这些数字的乘积
if (prod[pj] / prod[pi - 1] + sum[n] - sum[pj] + sum[pi - 1] > maxn) {
maxn = prod[pj] / prod[pi - 1] + sum[n] - sum[pj] + sum[pi - 1];
L = pi;
R = pj;
}
}
}
cout << L << ' ' << R << "\n";
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T = 1;
cin >> T; cin.get();
while (T --) solve();
return 0;
}