第二题:MILK EXCHANGE
标签:思维、倍增
题意:给定
N
N
N个数围成环。第
i
i
i个右边是第
i
+
1
i+1
i+1,左边是第
i
−
1
i-1
i−1。特殊的是第
1
1
1个数 左边是第
N
N
N个数,第
N
N
N个数右边是第
1
1
1个数。初始 第
i
i
i个数为
a
i
a_i
ai。给定一个字符串
s
1
,
s
2
,
.
.
.
s
n
s_1,s_2,...s_n
s1,s2,...sn,对于第
i
i
i个字符
s
i
s_i
si要么为
L
L
L,要么为
R
R
R。对于
s
i
=
L
s_i=L
si=L的情况下,
a
i
a_i
ai每分钟传递
1
1
1的值给左边;对于
s
i
=
R
s_i=R
si=R的情况下,
a
i
a_i
ai每分钟传递
1
1
1的值给右边。传递都是同时进行的。
传递的过程如果如果值超过了 初始的
a
i
a_i
ai将会溢出,求经过
M
M
M分钟之后 这些所有数值之和为多少。
(
1
≤
N
≤
2
∗
1
0
5
,
1
≤
M
,
a
i
≤
1
0
9
1 ≤ N ≤ 2 * 10^5,1 ≤ M,a_i ≤ 10^9
1≤N≤2∗105,1≤M,ai≤109)
题解:数据很大,模拟每一分钟肯定不现实。我们先观察下一个例子
4 1
RRLL
1 1 1 1
初始
a
i
a_i
ai都是
1
1
1,求第
1
1
1分钟之后 数值之和。
第
1
1
1分钟的时候,
1
1
1往
2
2
2流,
2
2
2往
3
3
3流;
4
4
4往
3
3
3流,
3
3
3往
2
2
2流。我们能发现对于第
2
2
2个和第
3
3
3个来说是没有损失的。但是对于第
1
1
1个和第
4
4
4个来说损失了
1
1
1。
推一推能看出来,对于
R
R
R
R
L
L
L
L
L
L
RRRRLLLLLL
RRRRLLLLLL的,左边连续
R
R
R和右边连续
L
L
L都是流向中间
R
L
RL
RL的地方,然后分别溢出的。那溢出多少呢?是不是和时间
M
M
M相关。那我们其实就去把所有的
R
L
RL
RL找到,然后往左和往右,两边连续的
R
R
R和
L
L
L分别溢出
M
M
M减去,再求下和即可。注意特判一下全
L
L
L和全
R
R
R的情况。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5 + 10;
string s;
ll cntl = 0, cntr = 0;
ll a[N], n, m, ans = 0, sum = 0;
int main() {
cin >> n >> m;
cin >> s;
for (int i = 1; i <= n; i++) {
cin >> a[i];
sum += a[i];
if (s[i - 1] == 'L') cntl++;
else cntr++;
a[i + n] = a[i + 2*n] = a[i]; // 倍增
}
if (cntl == n || cntr == n) {
cout << sum << endl;
return 0;
}
s = "@" + s + s + s; // 环 倍增处理
for (int i = 1; i <= n; i++) {
if (s[i] == 'R' && s[i + 1] == 'L') {
ll l = i + n, r = i + 1 + n;
ll suml = 0, sumr = 0;
while (l > 1 && s[l - 1] == 'R') {
l--;
suml += a[l];
}
while (r < 3 * n && s[r + 1] == 'L') {
r++;
sumr += a[r];
}
// m轮之后 左边连续L剩余的 + 右边连续R剩余的
ll leave = max(suml - m, 0ll) + max(sumr - m, 0ll);
ans += a[i] + a[i + 1] + leave; // i和i+1位置牛奶量不变保留
}
}
cout << ans << endl;
return 0;
}