对于整数数组[a1,a2,…,an],我们称之为价值|a1−a2|+|a2−a3|+⋯+|an−1−an|这对比数组的。注意数组大小的对比1等于0. 给你一个整数数组a。你的任务是建立一个数组b满足以下所有条件: b不为空,即至少有一个元素; b是的子序列a,即b可以通过从中删除一些元素来产生a(可能是零); 的对比b等于的对比a. 阵列的最小可能大小是多少b? 投入 第一行包含一个整数t (1≤t≤104)—测试用例的数量。 每个测试用例的第一行包含一个整数n (1≤n≤3⋅105)—数组的大小a. 第二行包含n整数a1,a2,⋅,an (0≤ai≤109)—数组本身的元素。 的总和n所有测试案例不超过3⋅105. 输出 对于每个测试用例,打印一个整数——数组的最小可能大小b.c++实现
时间: 2023-06-18 11:04:15 浏览: 86
题目翻译:
给定一个整数数组a,定义数组的价值为|a1−a2|+|a2−a3|+⋯+|an−1−an|,现在你需要构造一个非空的子序列b,使得b的价值等于a的价值,求b的最小可能大小。
思路:
对于一个长度为n的数组a,我们可以考虑从a的中间位置开始往两边扩展,对于每个位置i,我们可以将a分成两个子数组:a[0:i]和a[i:n-1],然后分别计算这两个子数组的价值,设它们分别为v1和v2,那么b的价值就为v1+v2。我们需要找到一个位置i,使得v1和v2的差值最小,即|v1-v2|最小。
为了方便计算,我们可以先计算出数组a中相邻元素之间的差值d[i]=|a[i]-a[i-1]|,那么a的价值就可以表示为v=sum(d[i]),b的价值也可以表示为v1+v2=sum(d[i]),其中v1=sum(d[i])*x,v2=sum(d[i])*(1-x),x表示a[0:i]中元素在b中出现的比例。
我们可以对x进行二分搜索,找到一个最小的x使得|v1-v2|最小,此时b的大小即为b的长度为2*mid+1,其中mid为最小的满足|v1-v2|<=v/2的位置i。
代码实现:
```c++
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
int main() {
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n), d(n-1);
for (int i = 0; i < n; i++) cin >> a[i];
for (int i = 1; i < n; i++) d[i-1] = abs(a[i]-a[i-1]);
int v = accumulate(d.begin(), d.end(), 0);
int l = 0, r = n-1, mid;
while (l < r) {
mid = (l+r)/2;
int v1 = accumulate(d.begin(), d.begin()+mid, 0);
int v2 = v-v1;
if (v1 > v2) r = mid;
else l = mid+1;
}
int v1 = accumulate(d.begin(), d.begin()+l, 0);
int v2 = v-v1;
double x = 0.5;
for (int i = 0; i < 50; i++) {
double x1 = x-0.25, x2 = x+0.25;
if (x1 < 0) x1 = 0;
if (x2 > 1) x2 = 1;
double v11 = v1*x1, v12 = v1*x2;
double v21 = v2*(1-x1), v22 = v2*(1-x2);
double d1 = abs(v11+v21-v22-v12);
double d2 = abs(v11+v22-v21-v12);
if (d1 < d2) x = x1;
else x = x2;
}
int ans = 2*l+1;
cout << ans << endl;
}
return 0;
}
```
阅读全文