这道题是要算一个环形,把L都移动到一起的最小代价。
枚举蓝色的分割点,那么它左侧右侧的L都向他靠拢(即箭头所示)可以得到一个最优的分割点(红色)
那么蓝色分割点顺时针移动,红色也会顺时针移动(类似旋转卡壳对冲点)
于是我们在O(n)的时间即可算出每一个蓝色分割点的最优解。
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstring>
using namespace std;
class LeftAndRightHandedDiv1 {
public:
long long countSwaps(string, int, int, int, int, int);
};
long long T[1000005];
char s[2000005];
int n;
int nt[2000005];
long long LeftAndRightHandedDiv1::countSwaps(string Y, int A, int B, int C,
int D, int N) {
n = N;
int l = Y.size();
int i, j, k;
T[0] = A;
for (i = 1; i < n; ++i)
T[i] = (T[i - 1] * B + C) % D;
int L = 0, R = 0;
for (i = 0; i < n; ++i) {
s[i + n] = s[i] = Y[T[i] % l];
if (s[i] == 'L')
L++;
if (s[i] == 'R')
R++;
}
s[2 * n] = 0;
if (L <= 1 || R <= 1)
return 0;
k = -1;
for (i = 2 * n - 1; i >= 0; --i) {
if (s[i] == 'L')
k = i;
nt[i] = k;
}
int lL, rL, lR, rR;
lL = rL = lR = rR = 0;
long long ans, cost;
cost = 0;
for (j = n - 1; j >= 0; --j) {
if (s[j] == 'R')
lR++;
else {
cost += lR;
lL++;
}
}
ans = cost;
j = 0;
for (i = 0; i < n; ++i) {
while (1) {
long long newcost;
int k = nt[j];
if (k == -1 || k >= i + n)
break;
newcost = cost - (lR - (k - j)) + rR + (k - j);
if (newcost > cost)
break;
cost = newcost;
lR -= k - j;
rR += k - j;
j = nt[j] + 1;
lL--;
rL++;
}
ans = min(ans, cost);
if (s[i] == 'L') {
lL++;
rL--;
} else {
cost += lL;
cost -= rL;
lR++;
rR--;
}
}
return ans;
}