第三题:BALANCING BACTERIA
标签:思维、差分
题意:给定nnn个数,a1,a2,a3...ana_1,a_2,a_3...a_na1,a2,a3...an,每次操作 可以选择数字 L(1<=L<=n)L(1<=L<=n)L(1<=L<=n),并选择增加或者减少。
比如增加的情况,从第nnn个数开始,第nnn个数增加LLL,第n−1n-1n−1个数增加L−1L-1L−1,第n−2n-2n−2个数增加L−2L-2L−2…,依次类推,直到增加值为000,再往前就不增加(即第111个到第n−Ln-Ln−L个数不增加值)
求将所有数变成 000的最少操作次数。(1<=n<=2∗105,10−15<=ai<=10151<=n<=2*10^5,10^{-15}<=a_i<=10^{15}1<=n<=2∗105,10−15<=ai<=1015)
举个例子:比如有两个数 −1 3-1\ \ \ 3−1 3
可以先从选择数字L=1L=1L=1并进行减少,操作555次,把序列变成:−1 −2-1\ \ \ \ -2−1 −2
然后选择数字L=2L=2L=2,并进行增加,操作111次,把序列变成:0 00\ \ \ 00 0。总共666次操作。
题解:以样例222为例,有555个数:1 3 −2 −7 51\ \ \ 3 \ \ -2 \ \ -7 \ \ \ 51 3 −2 −7 5
我们维护一个差分数组bib_ibi为ai−ai−1a_i-a_{i-1}ai−ai−1:1 2 −5 −5 121\ \ \ 2 \ \ -5 \ \ -5 \ \ \ 121 2 −5 −5 12
这个差分数组表示原aaa数组中相邻两个数的差值,我们额外对i=1i=1i=1的时候求b1=a1−a0b_1=a_1-a_0b1=a1−a0,a0=0a_0=0a0=0。
再对差分数组bib_ibi做差分,ci=bi−bi−1c_i=b_i-b_{i-1}ci=bi−bi−1:1 1 −7 0 171 \ \ 1 \ \ -7 \ \ 0 \ \ 171 1 −7 0 17
原aia_iai:1 3 −2 −7 51\ \ \ 3 \ \ -2 \ \ -7 \ \ \ 51 3 −2 −7 5
第111轮aia_iai:−1 −2 −3 −4 −5=>0 1 −5 −11 0-1\ -2\ -3\ -4 \ -5=> 0\ \ \ 1 \ \ -5 \ \ -11 \ \ \ 0−1 −2 −3 −4 −5=>0 1 −5 −11 0 (操作次数+1+1+1)
第222轮aia_iai:0 −1 −2 −3 −4=>0 0 −7 −14 −40\ -1\ -2\ -3 \ -4=> 0\ \ \ 0 \ \ -7 \ \ -14 \ \ \ -40 −1 −2 −3 −4=>0 0 −7 −14 −4 (操作次数+1+1+1)
第333轮aia_iai:0 0 1 2 3=>0 0 0 0 170\ 0\ 1\ 2 \ 3=> 0\ \ \ 0 \ \ 0 \ \ 0 \ \ \ 170 0 1 2 3=>0 0 0 0 17 (操作次数+7+7+7)
第444轮aia_iai:0 0 0 0 0=>0 0 0 0 170\ 0\ 0\ 0 \ 0=> 0\ \ \ 0 \ \ 0 \ \ 0 \ \ \ 170 0 0 0 0=>0 0 0 0 17 (操作次数+0+0+0)
第555轮aia_iai:0 0 0 0 −1=>0 0 0 0 00\ 0\ 0\ 0 \ -1=> 0\ \ \ 0 \ \ 0 \ \ 0 \ \ \ 00 0 0 0 −1=>0 0 0 0 0 (操作次数+17+17+17)
我们能够发现每次归000的操作次数就是对应cic_ici的绝对值。其实就是对bib_ibi进行差分,得到每个对应的后缀需要修改多少。
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
ll a[N], b[N], n, ans = 0;
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
b[i] = a[i] - a[i - 1]; // 差分
}
for (int i = 1; i <= n; i++) {
ans += abs(b[i] - b[i - 1]);
}
cout << ans << endl;
return 0;
}