反悔贪心:ABC 464 G

https://atcoder.jp/contests/abc464/tasks/abc464_g

考虑初始时是怎样的

我们从左往右,如果一个位置修改能使答案+1,那么我们就修改。此时的代价为1.

修改完后的序列肯定长这个样子的:

黄色是我们已经构造的连续段,红色是单独的一个,蓝色是单独的2个

此时在这个阶段,我们修改蓝色是最优的,代价为2。

接下来会变成这样:

接下来,我们的每次操作,一定是把两个红色合并在一起。那么中间的黄色部分我们就是按照一开始的序列来计算代价。

我们记 f ( l , r ) f(l,r) f(l,r) 表示在原序列 的基础上,把 l , r l,r l,r 区间变成101010的序列需要多少步。

每个黄色段的代价,就是 f ( l − 1 , r + 1 ) − f ( l , r ) f(l-1,r+1)-f(l,r) f(l−1,r+1)−f(l,r),直接丢到优先队列里面就行。

每次取出来用链表合并一下。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
#ifdef LOCAL
 #define debug(...) fprintf(stdout, ##__VA_ARGS__)
#else
 #define debug(...) void(0)
#endif
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define Z(x) (x)*(x)
#define pb push_back
#define fi first
#define se second
//#define M
//#define mo
#define N 2000010
struct node {
	int l, r, cost, id; 
	bool operator < (const node A) const {
		if(cost == A.cost) return l < A.l; 
		return cost > A.cost; 
	}
};
int n, m, i, j, k, T;
char str[N]; 
int S[N][2], a[N], b[N], c[N], L[N], R[N], Fee[N]; 
int ans, tot, cnt1, cnt2, bas, sum, id[N], pos[N]; 
int L1, R1, L2, R2; 
vector<int>v;  
priority_queue<node>s; 

int f(int l, int r) {
	int ans = 0, len, le1, le2; 
	len = r - l + 1; 
	le1 = (len + 1) / 2; le2 = len / 2; 
	ans += le1 - (S[r][l & 1] - S[l - 1][l & 1]); 
	ans += S[r][l & 1 ^ 1] - S[l - 1][l & 1 ^ 1]; 
	return ans; 
}

signed main()
{
	#ifdef LOCAL
	  freopen("in.txt", "r", stdin);
	  freopen("out.txt", "w", stdout);
	#endif
//	srand(time(NULL));
	T = read();
	while(T--) {
		auto init = [&] () -> void {
			v.clear(); 
			while(!s.empty()) s.pop(); 
			for(i = 0; i <= n + 2; ++i) {
				c[i] = a[i] = b[i] = S[i][0] = S[i][1] = 0; 
				L[i] = R[i] = 0; id[i] = pos[i] = 0; 
			}
			a[0] = a[n + 1] = a[n + 2] = -1; 
			cnt1 = cnt2 = bas = sum = 0; 
		}; 
		n = read(); init(); 
		scanf("%s", str + 1); 
		for(i = 1; i <= n; ++i) 
			a[i] = (str[i] == 'R' ? 1 : 0); 
		for(i = 1; i <= n; ++i) debug("%d", a[i]); debug("\n");  
		for(i = 1; i <= n; ++i) {
			S[i][0] = S[i - 1][0]; S[i][1] = S[i - 1][1]; 
			S[i][i & 1] += a[i]; 
			if(a[i] == 0 && a[i - 1] == 1) bas++; 
		}
		for(i = 0; i <= n + 2; ++i) b[i] = a[i]; 
		for(i = 1; i <= n; ++i) {
			if(b[i - 1] == 1 && b[i] == 1 && b[i + 1] != 0) b[i] = 0, ++cnt1; 
			else if(b[i] == 0 && b[i + 1] == 0 && b[i - 1] != 1) b[i] = 1, ++cnt1; 
		}
		for(i = 1; i <= n; ++i) 
			if(b[i] == 1 && b[i + 1] == 0)
				c[i] = c[i + 1] = 1; 
		for(i = 1; i <= n; ++i) debug("%d", b[i]); debug("\n");  
		for(i = 1; i < n; ++i) 
			if(!c[i] && !c[i + 1]) 
				b[i] = 1, b[i + 1] = 0, c[i] = c[i + 1] = 1, cnt2++; 
		for(i = 1; i <= n; ++i) debug("%d", b[i]); debug("\n");  
		debug("cnt1 : %d cnt2 : %d\n", cnt1, cnt2); 
		
		for(i = 1; i <= n; ++i) 
			if(c[i]) L[i] = R[i] = i; 
		for(i = 1; i <= n; ++i) 
			if(c[i] && L[i - 1]) L[i] = L[i - 1]; 
		for(i = n; i >= 1; --i) 
			if(c[i] && R[i + 1]) R[i] = R[i + 1];  
		for(i = 1; i <= n; ++i) debug("%d ", L[i]); debug("\n");  
		for(i = 1; i <= n; ++i) debug("%d ", R[i]); debug("\n");  
		for(i = 2; i <= n; ++i) 
			if(L[i] == i && R[i] != n) {
				Fee[i] = f(L[i] - 1, R[i] + 1) - f(L[i], R[i]); 
				s.push({L[i], R[i], Fee[i], pos[i] = ++sum}); 
				debug("[%d %d] %d\n", L[i], R[i], Fee[i]); 
			}
		while(!s.empty()) {
//			debug(">>>>>> %d\n", s.size()); 
			auto t = s.top(); s.pop(); 
			if(id[t.id]) continue; 
			id[t.id] = 1; 
			v.pb(t.cost); 
			R1 = t.l - 2; L1 = L[R1]; 
			L2 = t.r + 2; R2 = R[L2]; 
			debug("Cal[%d %d] (%d) [%d %d] [%d %d]\n", t.l, t.r, t.cost, L1, R1, L2, R2); 
			R[L1] = R2; L[R2] = L1; 
			if(L1 > 1 && R1 && L1 < R1) id[pos[L1]] = 1, debug("Er[%d %d]\n", L1, R1); 
			if(R2 < n && L2 != n + 1 && R2 && L2 < R2) id[pos[L2]] = 1, debug("Er[%d %d]\n", L2, R2); 
			if(L1 > 1 && R2 < n && R1 != 0 && L2 != n + 1 && R2 && L1 < R2) {
				Fee[L1] = f(L1 - 1, R2 + 1) - f(L1, R2); 
				s.push({L1, R2, Fee[L1], pos[L1] = ++sum}); 
				debug("Put[%d %d]\n", L1, R2); 
			}
//			debug(">>>>>> %d\n", s.size()); 
		}
		tot = 0; ans = bas; printf("%d ", ans); 
		while(cnt1--) ++tot, ++ans, printf("%d ", ans); 
		while(cnt2--) {
			printf("%d %d ", ans, ans + 1); tot += 2; ++ans; 
		}
//		debug("Now(%d) ", ans); 
		for(auto t : v) {
			while(t > 1) --t, printf("%d ", ans), ++tot; 
			printf("%d ", ans + 1); ++ans;  ++tot; 
		}
		while(tot < n) printf("%d ", ans), ++tot; 
		printf("\n");   
	}
	
	return 0;
}