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;
}