Loading

qoj.2626 Kilk Not 做题记录

link

连续性相关的题目。

先二分连续段的长度 \(mid\) 并判定。如何判定呢,可以求出使用的 \(\mathtt 1\) 数量的最小值和最大值。

记最终串中 \(\mathtt 1\) 的数量为 \(k\),记这两个值分别为 \(k_{\min}, k_{\max}\),如果 \(k < k_{\min}\)\(k_{\max} < k\) 显然无解。

接下来我们证明否则一定有解。考虑 \(\mathtt 1\) 数量最小的最大的情况下,串分别为 \(s_{\min}, \ s_{\max}\),我们找一个分界点 \(0\le i\le n\) 然后拼接 \(s_{\min} [1 : i] + s_{\max} [i + 1 : n]\),满足拼接后的串中 \(\mathtt 1\) 的数量为 \(k\)

还有一个问题,如果 \(s_{\min}[i] = s_{max} [i + 1]\) 就寄了,接下来我们证明一定存在一个合法的 \(i\) 满足 \(s_{\min}[i] \not = s_{\max}[i + 1]\)

记最后一个满足 \(\mathtt 1\) 的数量为 \(k\) 的拼接分界点为 \(p\),那么有 \(s_{\max}[p + 1] = \mathtt 1, \ s_{\min}[p + 1] = \mathtt 0\)。若 \(s_{\max}[p] = \mathtt 1\) 则万事大吉,否则 \(s_{\max}[p] = \mathtt 0\),向前找到第一个位置 \(q\) 满足 \(s_{\max}[q], s_{\min}[q]\) 中至少有一个 \(\mathtt 1\)。如果 \(s_{\max}[q] = \mathtt 1\) 则显然可以取 \(q\) 为分界点,否则此时有 \(s_{\max}[q] = \mathtt 0, \ s_{\min}[q] = \mathtt 1\),那么当 \(q - 1\) 为分界点时拼出来的串的 \(\mathtt 1\) 的数量为 \(k + 1\),我们可以继续往前找 \(p\),不断重复,总会有尽头。

DP 使用单调队列优化,时间复杂度 \(\mathcal O(n\log n)\)


启示:感觉这个 \([k_{\min}, k_{\max}]\) 连续性很厉害啊,被教育了。


点击查看代码
#include <bits/stdc++.h>
#define ll int
#define LL long long
#define uLL unsigned LL
#define fi first
#define se second
#define mkp make_pair
#define pir pair<ll, ll>
#define pb push_back
#define i128 __int128
using namespace std;
template <class T>
const inline void rd(T &x) {
    char ch;
    bool neg = 0;
    while (!isdigit(ch = getchar()))
        if (ch == '-')
            neg = 1;
    x = ch - '0';
    while (isdigit(ch = getchar())) x = (x << 1) + (x << 3) + ch - '0';
    if (neg)
        x = -x;
}
const ll maxn = 3e5 + 10, mod = 998244353, iv = mod - mod / 2, inf = 1e9;
ll power(ll a, ll b = mod - 2, ll p = mod) {
    ll s = 1;
    while (b) {
        if (b & 1)
            s = 1ll * s * a % p;
        a = 1ll * a * a % p, b >>= 1;
    }
    return s;
}
template <class T, class _T>
const inline ll pls(const T x, const _T y) { return x + y >= mod ? x + y - mod : x + y; }
template <class T, class _T>
const inline ll mus(const T x, const _T y) { return x < y ? x + mod - y : x - y; }
template <class T, class _T>
const inline void add(T &x, const _T y) { x = x + y >= mod ? x + y - mod : x + y; }
template <class T, class _T>
const inline void sub(T &x, const _T y) { x = x < y ? x + mod - y : x - y; }
template <class T, class _T>
const inline void chkmax(T &x, const _T y) { x = x < y ? y : x; }
template <class T, class _T>
const inline void chkmin(T &x, const _T y) { x = x < y ? x : y; }

ll T, n, a, b, lst[maxn][2], f0[maxn], f1[maxn], k;
ll q0[maxn], l0, r0, q1[maxn], l1, r1, jc0[maxn], jc1[maxn];
char str[maxn], smin[maxn], smax[maxn];

bool check(ll mid) {
	l0 = l1 = 1, r0 = r1 = 0;
	for(ll i = 1; i <= n; i++) {
		ll p0 = max(lst[i][1], i - mid), p1 = max(lst[i][0], i - mid);
		while(l0 <= r0 && f1[i - 1] < f1[q0[r0]]) --r0;
		q0[++r0] = i - 1;
		while(l0 <= r0 && q0[l0] < p0) ++l0;
		if(l0 <= r0) {
			ll x = jc0[i] = q0[l0];
			f0[i] = f1[x];
		} else f0[i] = inf;
		while(l1 <= r1 && f0[i - 1] - (i - 1) < f0[q1[r1]] - q1[r1]) --r1;
		q1[++r1] = i - 1;
		while(l1 <= r1 && q1[l1] < p1) ++l1;
		if(l1 <= r1) {
			ll x = jc1[i] = q1[l1];
			f1[i] = i - x + f0[x];
		} else f1[i] = inf;
	}
	smin[n + 1] = 0;
	ll kmin = min(f0[n], f1[n]), pos = n, c = (f0[n] > f1[n]);
	while(pos) {
		ll lst = (c? jc1[pos] : jc0[pos]);
		for(ll i = lst + 1; i <= pos; i++) smin[i] = '0' + c;
		pos = lst, c ^= 1;
	}
	l0 = l1 = 1, r0 = r1 = 0;
	for(ll i = 1; i <= n; i++) {
		ll p0 = max(lst[i][1], i - mid), p1 = max(lst[i][0], i - mid);
		while(l0 <= r0 && f1[i - 1] > f1[q0[r0]]) --r0;
		q0[++r0] = i - 1;
		while(l0 <= r0 && q0[l0] < p0) ++l0;
		if(l0 <= r0) {
			ll x = jc0[i] = q0[l0];
			f0[i] = f1[x];
		} else f0[i] = -inf;
		while(l1 <= r1 && f0[i - 1] - (i - 1) > f0[q1[r1]] - q1[r1]) --r1;
		q1[++r1] = i - 1;
		while(l1 <= r1 && q1[l1] < p1) ++l1;
		if(l1 <= r1) {
			ll x = jc1[i] = q1[l1];
			f1[i] = i - x + f0[x];
		} else f1[i] = -inf;
	}
	smax[n + 1] = 0;
	ll kmax = max(f0[n], f1[n]); pos = n, c = (f0[n] < f1[n]);
	while(pos) {
		ll lst = (c? jc1[pos] : jc0[pos]);
		for(ll i = lst + 1; i <= pos; i++) smax[i] = '0' + c;
		pos = lst, c ^= 1;
	}
	return kmin <= k && k <= kmax;
}

void solve() {
	rd(n), rd(a), rd(b), scanf("%s", str + 1);
	k = b;
	for(ll i = 1; i <= n; i++) {
		lst[i][0] = lst[i - 1][0], lst[i][1] = lst[i - 1][1];
		if(str[i] != '?') lst[i][str[i] - '0'] = i;
		if(str[i] == '1') ++k;
	}
	ll lo = 1, hi = n;
	while(lo <= hi) {
		ll mid = lo + hi >> 1;
		if(check(mid)) hi = mid - 1;
		else lo = mid + 1;
	}
	check(lo); printf("%d\n", lo);
	ll cnt = 0;
	for(ll i = 1; i <= n; i++) cnt += smin[i] - '0';
	for(ll i = 0; i <= n; i++) {
		if(i) cnt += smax[i] - smin[i];
		if(cnt == k && smax[i] != smin[i + 1]) {
			for(ll j = 1; j <= i; j++) putchar(smax[j]);
			puts(smin + i + 1);
			break;
		}
	}
}

int main() {
	rd(T); while(T--) solve();
	return 0;
}
posted @ 2025-11-03 15:41  Sktn0089  阅读(2)  评论(0)    收藏  举报