SRM 612



这道题是要算一个环形,把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;
}


你可能感兴趣的:(topcoder,SRM)