0回文数组 - 蓝桥云课
问题描述
小蓝在无聊时随机生成了一个长度为 n 的整数数组,数组中的第 i 个数为 ai,他觉得随机生成的数组不太美观,想把它变成回文数组,也就是对于任意 i∈[1,n] 满足 ai=an−i+1。小蓝一次操作可以指定相邻的两个数,将它们一起加1或减1;也可以只指定一个数加1或减1,请问他最少需要操作多少次能把这个数组变成回文数组?
输入格式
输入的第一行包含一个正整数 n。
第二行包含 n 个整数 a1,a2,...,an,相邻整数之间使用一个空格分隔。
输出格式
输出一行包含一个整数表示答案。
样例输入
4
1 2 3 4
样例输出
3
样例说明
第一次操作将 a1,a2 加1,变为 2, 3, 3, 4;
后面两次操作将 a1 加1,变为 4, 3, 3, 4。
评测用例规模与约定
- 对于 20% 的评测用例,1≤n≤10;
- 对于所有评测用例,1≤n≤10^5,−10^6≤ai≤10^6。
思路:
差点的贪心,8/12的测试点
代码:
#include <iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const ll N = 1e5+10;
ll n,a[N],ans;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n;
for(ll i = 1 ; i <= n ; i++)
cin >> a[i];
ll l = 1,r = n;
while(l < r)
{
if(a[l] == a[r])
{
l++,r--;
}
else if(abs(a[l] - a[r]) >= abs(a[l+1] - a[r-1]))
{
ans += abs(a[l] - a[r]);
a[l+1] = a[r-1];
l++,r--;
}
else
{
ans += abs(a[l] - a[r]);
if(a[l+1] > a[r-1])
{
a[r-1] += abs(a[l] - a[r]);
}
else if(a[l+1] < a[r-1])
{
a[l+1] += abs(a[l] - a[r]);
}
else
{
cout << "报错" << endl;
}
l++,r--;
}
}
cout << ans;
return 0;
}
思路:
可以对数组进行相减n/2的长度。这样是最贪心的
代码:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin >> n;
vector<ll> a(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
int m = n / 2;
vector<ll> d(m);
for (int i = 0; i < m; ++i) {
int j = n - 1 - i;
d[i] = a[i] - a[j];
}
ll ans = 0;
for (int i = 0; i < m; ++i) {
if (d[i] == 0) continue;
if (i + 1 < m) {
if ((d[i] > 0 && d[i+1] > 0) || (d[i] < 0 && d[i+1] < 0)) {
ll k = min(abs(d[i]), abs(d[i+1]));
if (d[i] > 0) {
d[i] -= k;
d[i+1] -= k;
} else {
d[i] += k;
d[i+1] += k;
}
ans += k;
}
}
ans += abs(d[i]);
d[i] = 0; // 已经处理完毕,置零避免重复处理
}
cout << ans << endl;
return 0;
}