1807: 减一(New Online Judge)
题目描述
给定长度为n的数组a,每次可以选择相邻的两个数字进行减1。
最少执行多少次上述操作,使得所有数字都相同,不可以为负数。
输入
输入第一行为正整数T,表示存在T组测试数据。T不超过100。
对于每组测试数据第一行输入正整数n,第二行包含n个数字表示数组a。(1≤n≤100000,0≤ai≤ 1 0 9 10^9 109)
输入保证T组数据的n的总和不超过100000。
50%的数据满足n为偶数,50%的数据满足n为奇数
输出
对于每组测试数据,如果无解输出-1,否则输出最少操作次数
样例输入
4
3
0 1 0
2
1 2
6
3 5 3 3 5 3
3
8 10 5
样例输出
-1
-1
8
7
题解1(C++版本)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
const LL INF = 1e18 +7;
int t, n;
LL ans = INF, a[N], b[N]; //最终操作次数可能会超出int类型的范围最大值
bool check(LL x){ //尝试使数组a中所有的元素都等于x,需要的总操作次数
LL sum = 0;
for(int i = 1; i <= n; i++) b[i] = a[i];
for(int i = 1; i <= n; i++){
if(b[i] < x) return false;
sum += (b[i] - x); //对相邻的前一个数进行操作
if(i < n) b[i + 1] -= (b[i] - x); //相邻的后面一个数要进行更新
}
if(b[n] == x) ans = min(ans, sum);
return true;
}
int main(){
scanf("%d", &t);
while(t--){
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
ans = INF;
LL L = -1, R = INF, mid;
while(L + 1 < R){
mid = (R + L)/2;
if(check(mid)) L = mid;
else R = mid;
}
if(ans == INF) ans = -1;
printf("%lld\n", ans);
}
return 0;
}