ARC129 d-1+2-1

题目链接:

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])

解题思路:

我们很容易想到,如果\sum_{i = 1}^{n}a[i] != 0 无解

首先,我们令Ai为ai修改的次数(不一定最小Ai>=0);

因此对于i,我们可以轻易的出;2 * A[i] - A[i+1] - A[i] = -a[i]                                  (1-1)

移项得:(A[i+1]-A[i]) - (A[i] - A[i-1]) = a[i]                                                       (1-2)

b[i] = A[i+1] - A[i]                                                                                                      (2-1)

\sum A[i]是我们要求的答案,因此我们要求出b[i]

b[i] - b[i-1] = a[i]                                                                                                            (2-2)

累加可得:

b[i] = \sum_{j = 1}^{i}a[j] + b[1] - a[1];                                                                                               (2-3)

再累加可得:\sum_{i = 1}^{n}b[i] = n * (b[1] - a[1]) + i * \sum_{j = 1}^{i}a[i]                                                      (2-4)

整理可得:

\sum_{i = 1}^{n}b[i] = n * b[1] - \sum_{i = 2}^{n}(n + 1 - i) * a[i]                                                                         (2-5)

由公式(2-1)得

累加可得:

\sum_{i= 1}^{n}b[i] = A[n + 1] - A[1] = 0                                                                                          (2-6)

带入公式(2-5)

b[1] =\frac{\sum_{i = 2}^{n}(n + 1 - i) * a[i]}{n}(必须整除,不然无解)                                                    (2-7)

就可以由公式(2-3)得到数组b

回看前面数组A的定义,由于A[i]是第i个数的操作次数,又因为我们需要总操作次数最小。

这样的话,其实我们要找到一个数x,令A[x]=0,实际上对于每个i,答案最小为A[i] - A[x]。

总答案为\sum_{i = 1}^{n}A[i] - n * A[x]

令c[i] = A[i] - A[x];

为了方便计算,我们令x的初值为1,这样的话我们发现

对于i = 0,c[1] = 0;

对于i >= 2 c[i] = c[i - 1] + b[i - 1];

因此要找到一个x满足\sum_{i = 1}^{n}A[i] - n * A[x]最小

即找到最小的c[i]为minn,对于每个c[i] -= minn

再将c[i]求和就为答案\sum_{i = 1}^{n}A[i] - n * A[x]

代码实现:

#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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值