题目链接:
D - -1+2-1
题目大意:
给n个数,每轮可以选择第i个数,给a[i-1], a[i], a[i+1]分别加上-1,2,-1,问最少经过多少轮,使每个元素都为0。(a[0] = a[n],a[n + 1] = a[1])
解题思路:
我们很容易想到,如果 无解
首先,我们令Ai为ai修改的次数(不一定最小Ai>=0);
因此对于i,我们可以轻易的出; (1-1)
移项得: (1-2)
令 (2-1)
是我们要求的答案,因此我们要求出b[i]
(2-2)
累加可得:
(2-3)
再累加可得: (2-4)
整理可得:
(2-5)
由公式(2-1)得
累加可得:
(2-6)
带入公式(2-5)
(必须整除,不然无解) (2-7)
就可以由公式(2-3)得到数组b
回看前面数组A的定义,由于A[i]是第i个数的操作次数,又因为我们需要总操作次数最小。
这样的话,其实我们要找到一个数x,令A[x]=0,实际上对于每个i,答案最小为A[i] - A[x]。
总答案为
令c[i] = A[i] - A[x];
为了方便计算,我们令x的初值为1,这样的话我们发现
对于i = 0,c[1] = 0;
对于i >= 2 ;
因此要找到一个x满足最小
即找到最小的c[i]为minn,对于每个c[i] -= minn
再将c[i]求和就为答案
代码实现:
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main() {
ios::sync_with_stdio(0);
cin.tie(0);
int n;
cin >> n;
vector<int> a(n + 1, 0);
int sum = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum += a[i];
}
if (sum) {
cout << "-1";
return 0;
}
sum = 0;
for (int i = 2; i <= n; i++) {
sum += (n + 1 - i) * a[i];
}
if (sum % n) {
cout << "-1";
return 0;
}
sum *= -1;
vector<int> b(n + 1);
b[1] = (sum / n);
for (int i = 2; i <= n; i++) {
b[i] = a[i] + b[i - 1];
}
vector<int> c(n + 1, 0);
int minn = 0;
for (int i = 2; i <= n; i++) {
c[i] = c[i - 1] + b[i - 1];
minn = min(c[i], minn);
}
int ans = 0;
for (int i = 1; i <= n; i++) {
c[i] -= minn;
ans += c[i];
}
cout << ans << endl;
return 0;
}
本文介绍了一种算法,解决给定n个数的动态调整问题,通过最少的轮次操作,使得数组中每个元素最终变为0。关键步骤包括构造修改次数数组、确定最小操作次数和计算最终答案。通过代码实现详细展示了如何找到最优操作方案。
3600

被折叠的 条评论
为什么被折叠?



