10.28
思路:
模拟题,枚举向那个点靠拢。
显然只用考虑一种颜色算就好了。
每次向i号点靠拢,前一部分的点靠前,后一部分的点靠后。
然后模拟递推就好了。
这种拆环为链的题一般都要扩倍。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
#define N 1000010
using namespace std;
int len;
char s[N];
int a[N], cnt, num;
LL sum, pos, ans = (1LL << 61);
int main(){
freopen ("sushi.in", "r", stdin);
freopen ("sushi.out", "w", stdout);
int T; scanf("%d", &T);
while ( T-- ){
ans = (1LL << 61);
cnt = num = sum = 0;
scanf("%s", s+1);
len = strlen ( s+1 );
for(register int i=1; i<=len; i++){
a[i+len] = a[i] = (s[i] == 'R');
if(a[i] == 0) cnt++;//一共有多少个
}
int id = 0, flag = 0, idd; pos = len + 1;
for(register int i=1; i<=len; i++){
if(a[i] == 0){
if(flag == 1){
sum += len - (cnt - ++idd) - i;
continue;
}
id++;//第一个往后走的是第几个
if(i - id > len - (cnt - id) - i){
sum += len - (cnt - id) - i;
pos = i;//第一个往后走的pos
flag = 1; idd = id;//是第几个
}
else
sum += i - id, num++;//有num个向前
}
}
ans = min(ans, sum);
for(register int i=2; i<=len; i++){
if(a[i-1] == 1) sum -= num, sum += cnt - num;
if(a[i-1] == 0) {
num--; id--;
}
if(pos <= 2*len)//扩倍
for(register int j=pos; j<=2*len; j++){//
if(a[j] == 0){
if((j - i + 1) - id > len - (cnt - id) - (j - i + 1)) break;
else {
sum -= len - (cnt - id) - (j - i + 1);
sum += (j - i + 1) - id, num++, pos = j + 1, id++;
}
}
}
ans = min(ans, sum);
}
cout << ans << endl;
}
}