小蓝在无聊时随机生成了一个长度为 nn 的整数数组,数组中的第 ii 个数为 aiai,他觉得随机生成的数组不太美观,想把它变成回文数组,也是就对于任意 i∈[1,n]i∈[1,n] 满足 ai=an−i+1ai=an−i+1。
小蓝一次操作可以指定相邻的两个数,将它们一起加 11 或减 11;也可以只指定一个数加 11 或减 11,请问他最少需要操作多少次能把这个数组变成回文数组?
输入格式
输入的第一行包含一个正整数 nn。
第二行包含 nn 个整数 a1,a2,…,ana1,a2,…,an,相邻整数之间使用一个空格分隔。
输出格式
输出一行包含一个整数表示答案。
数据范围
对于 20%20% 的评测用例,1≤n≤101≤n≤10。
对于所有评测用例,1≤n≤1051≤n≤105,−106≤ai≤106−106≤ai≤106。
输入样例:
4
1 2 3 4
输出样例:
3
样例解释
第一次操作将 a1,a2a1,a2 加 11,变为 2,3,3,42,3,3,4;
后面两次操作将 a1a1 加 11,变为 4,3,3,44,3,3,4。
题解:
没有tag提示呜呜呜,看题目其实感觉像是动态规划来着,感觉看什么都像动态规划。
实际是贪心写的,遍历一半的数组,能同时两个操作就两个,不能就单独操作一个即可,比较简单的算法。
代码:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iomanip>
#include<queue>
#include<stack>
#include<vector>
#include<unordered_set>
#include<unordered_map>
#include<map>
#include<set>
using namespace std;
typedef long long int ll;
int n=0;
vector<int> vt(100005,0);
long long int cnt=0;
int main(){
cin >> n;
for(int i=0;i<n;i++){
cin >> vt[i];
}
long long int t=0;
for(int i=0;i<n/2;i++){
if(vt[i]==vt[n-i-1]){
continue;
}
int t1=i;int t2=n-i-1;
if(vt[t1]<vt[t2] && vt[t1+1]<vt[t2-1]){
t=min(vt[t2]-vt[t1],vt[t2-1]-vt[t1+1]);
vt[t1]+=t;vt[t1+1]+=t;
cnt+=t;i--;
}
else if(vt[t1]>vt[t2] && vt[t1+1]>vt[t2-1]){
t=min(vt[t1]-vt[t2],vt[t1+1]-vt[t2-1]);
vt[t1]-=t;vt[t1+1]-=t;
cnt+=t;i--;
}
else{
if(vt[i]<vt[n-i-1]){
t=vt[n-i-1]-vt[i];
vt[i]+=t;
cnt+=t;
}
else if(vt[i]>vt[n-i-1]){
t=vt[i]-vt[n-i-1];
vt[i]-=t;
cnt+=t;
}
i--;
}
}
cout << cnt <<"\n";
}