題解——USACO 24FEB B Milk Exchange
題意
有 \(N\) 頭奶牛圍成一圈,第 \(i\) 頭奶牛有一個容量為 \(a_i\) 的桶,初始時桶滿,每一時刻,每頭奶牛都會根據一個操作序列 \(s\) 來將自己桶中的 \(1\) 升牛奶倒給自己左邊或右邊的奶牛(如果桶里有牛奶的話),傳遞完之后,大于桶的容量那部分牛奶將會溢出,問 \(M\) 時刻后,所有的桶里一共還剩多少牛奶。
解析
如果 \(s_i\) 是 R,\(s_{i+1}\) 是 L,那么我們就將這兩個操作方向對應的兩頭奶牛稱為兩頭 “溢牛”,或一個 “溢牛對”。
為什么這樣稱呼呢?
注意到每次操作,溢牛對內部的總奶量不變,因為左邊的溢牛總是能給右邊的溢牛倒 \(1\) 升牛奶,右邊的溢牛也總是能給左邊的溢牛倒 \(1\) 升牛奶,相當于是每次互相交換 \(1\) 升牛奶。
這就意味著,只要有牛奶被傳遞給溢牛對,這部分牛奶必定溢出,因為溢牛對內部奶量總是滿的,故對于每一個溢牛對,只需求出可能被傳遞給它左右邊的奶量,分別對 \(m\) 取最小值即可求出每個溢牛對溢出的奶量。
其實就是求每個溢牛對左邊連續的 R 所對應的奶牛的奶量和右邊連續的 L 所對應的奶牛的奶量。
代碼
尤其注意奶牛們圍成一個圈。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
ll a[N],b[N];
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
ll n,m;
ll ans = 0,sum = 0;
cin>>n>>m;
string s;
cin>>s;
s = s[n - 1] + s;
for(int i=1;i<=n;i++){
cin>>a[i];
sum += a[i];
}
for(int i=0;i<=n;i++){
if(s[i] == 'R' && s[i + 1] == 'L'){
ll l = 0,r = 0;
int lpos = i - 1 <= 0 ? i - 1 + n : i - 1,rpos = i + 2 > n ? i + 2 - n : i + 2;
while(s[lpos] == 'R'){
l += a[lpos];
lpos--;
if(lpos <= 0) lpos += n;
}
while(s[rpos] == 'L'){
r += a[rpos];
rpos++;
if(rpos > n) rpos -= n;
}
// cout<<l<<' '<<r<<'\n';
ans += min(m,l) + min(m,r);
}
}
cout<<sum - ans;
return 0;
}

浙公網安備 33010602011771號