qoj.2626 Kilk Not 做题记录
连续性相关的题目。
先二分连续段的长度 \(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;
}

浙公网安备 33010602011771号