USACO 2024年2月铜组 MILK EXCHANGE(思维 倍增)

第二题:MILK EXCHANGE

标签:思维、倍增
题意:给定NNN个数围成环。第iii个右边是第i+1i+1i+1,左边是第i−1i-1i1。特殊的是第111个数 左边是第NNN个数,第NNN个数右边是第111个数。初始 第iii个数为aia_iai。给定一个字符串s1,s2,...sns_1,s_2,...s_ns1,s2,...sn,对于第iii个字符sis_isi要么为LLL,要么为RRR。对于si=Ls_i=Lsi=L的情况下,aia_iai每分钟传递111的值给左边;对于si=Rs_i=Rsi=R的情况下,aia_iai每分钟传递111的值给右边。传递都是同时进行的。
传递的过程如果如果值超过了 初始的aia_iai将会溢出,求经过MMM分钟之后 这些所有数值之和为多少。
1≤N≤2∗105,1≤M,ai≤1091 ≤ N ≤ 2 * 10^5,1 ≤ M,a_i ≤ 10^91N21051Mai109
题解:数据很大,模拟每一分钟肯定不现实。我们先观察下一个例子

4 1
RRLL
1 1 1 1

初始aia_iai都是111,求第111分钟之后 数值之和。
111分钟的时候,111222流,222333流;444333流,333222流。我们能发现对于第222个和第333个来说是没有损失的。但是对于第 111个和第444个来说损失了111

推一推能看出来,对于RRRRLLLLLLRRRRLLLLLLRRRRLLLLLL的,左边连续RRR和右边连续LLL都是流向中间RLRLRL的地方,然后分别溢出的。那溢出多少呢?是不是和时间MMM相关。那我们其实就去把所有的RLRLRL找到,然后往左和往右,两边连续的RRRLLL分别溢出MMM减去,再求下和即可。注意特判一下全LLL和全RRR的情况。
代码

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值