Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Think per mine, not per zero. A mine with value contributes once for each adjacent zero cell.
Start with the dumb fantasy world where every mined cell has four adjacent zero cells, so the total is . Then subtract every direction that fails. This turns the problem into computing reductions for every width .
Vertical mined-neighbor reductions depend on pairs of positions whose difference is exactly . That is screaming convolution: match digit values against reversed nonzero indicators.
For top/down missing neighbors, a mine at position loses upward for all and downward for all . Those are just two range adds over widths.
The horizontal mess is controlled by gaps. The gap between and is a row break exactly when . Both-mined gaps cost the same either way; mixed mine/zero gaps only cost when the gap is split.
Research checked: the canonical statement is the Codeforces problem page (https://codeforces.com/contest/2206/problem/F). The official tutorial PDF (https://codeforces.com/contest/2206/attachments/download/36244/analysis.pdf) gives the intended base-minus-reductions idea with convolution plus divisor/range handling. The public status page (https://codeforces.com/contest/2206/status/F) confirms accepted C++ submissions, though individual source pages were blocked by Codeforces browser checking here.
Let be the digit at position . A zero cell contributes nothing by itself; it only receives mine counts from adjacent mined cells. So for a fixed width ,
Start with for every mined cell, as if all four neighboring directions existed and were zero. Then subtract for each direction that fails because the neighbor is missing or because the neighbor also has mines. Thus
Now compute for all .
Vertical mined pairs
Cells and are vertical neighbors. If both contain mines, the base counted both directions incorrectly, so the reduction is . Equivalently,
Use one convolution. Define
Then the coefficient of in equals
and the coefficient of equals
So for , add both coefficients. Since coefficients are at most , one NTT modulo is exact. No floating-point clownery required.
Missing vertical neighbors
A mined cell at position has no upper neighbor iff , i.e. .
It has no lower neighbor iff , i.e. . This condition also handles the truncated bottom row correctly. Do not assume only cells in the last visual row lose downward adjacency; cells above missing columns can lose it too.
For every nonzero , add to both ranges with a difference array.
Horizontal gaps
Look at the gap between positions and , where . This gap is a row break exactly when .
If , the cells are horizontally adjacent. The only reduction from this gap happens when both endpoints are mined, costing .
If , they are not adjacent. The right side of and the left side of are missing, so the reduction is from whichever endpoints are mined.
Therefore:
Add the both-mined gap total to every width. For the remaining gaps, add their cost to every divisor width by looping over multiples: for each , visit .
Finally, the outer left side of cell and outer right side of cell are missing for every width, so add to every width.
After all reductions are known, compute
then use nth_element with descending order to get the -th largest value.
Edge cases are naturally covered: all zeros give all , gives because the single cell has no adjacent cells, makes every internal gap a row break, and makes one row with no vertical neighbors.
Complexity is time from the NTT and divisor/multiple loops, and memory.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MOD = 998244353;
const int ROOT = 3;
int modPow(ll a, ll e) {
ll r = 1;
while (e) {
if (e & 1) r = r * a % MOD;
a = a * a % MOD;
e >>= 1;
}
return (int)r;
}
void ntt(vector<int>& a, bool invert) {
int n = (int)a.size();
for (int i = 1, j = 0; i < n; i++) {
int bit = n >> 1;
for (; j & bit; bit >>= 1) j ^= bit;
j ^= bit;
if (i < j) swap(a[i], a[j]);
}
for (int len = 2; len <= n; len <<= 1) {
int wlen = modPow(ROOT, (MOD - 1) / len);
if (invert) wlen = modPow(wlen, MOD - 2);
for (int i = 0; i < n; i += len) {
ll w = 1;
for (int j = 0; j < len / 2; j++) {
int u = a[i + j];
int v = (int)(a[i + j + len / 2] * w % MOD);
int x = u + v;
if (x >= MOD) x -= MOD;
int y = u - v;
if (y < 0) y += MOD;
a[i + j] = x;
a[i + j + len / 2] = y;
w = w * wlen % MOD;
}
}
}
if (invert) {
int invN = modPow(n, MOD - 2);
for (int& x : a) x = (int)((ll)x * invN % MOD);
}
}
vector<int> convolution(vector<int> a, vector<int> b) {
int need = (int)a.size() + (int)b.size() - 1;
int n = 1;
while (n < need) n <<= 1;
a.resize(n);
b.resize(n);
ntt(a, false);
ntt(b, false);
for (int i = 0; i < n; i++) a[i] = (int)((ll)a[i] * b[i] % MOD);
ntt(a, true);
a.resize(need);
return a;
}
int main() {
setIO();
int n, k;
string s;
cin >> n >> k >> s;
vector<int> a(n), poly(n), revNonzero(n);
ll total = 0;
for (int i = 0; i < n; i++) {
a[i] = s[i] - '0';
total += a[i];
poly[i] = a[i];
revNonzero[n - 1 - i] = (a[i] > 0);
}
vector<int> conv = convolution(poly, revNonzero);
vector<ll> red(n + 2), diff(n + 3);
for (int p = 0; p < n; p++) {
if (!a[p]) continue;
diff[p + 1] += a[p];
diff[n + 1] -= a[p];
diff[n - p] += a[p];
diff[n + 1] -= a[p];
}
ll cur = 0;
for (int w = 1; w <= n; w++) {
cur += diff[w];
red[w] += cur;
}
ll horizontalAll = 0;
vector<int> splitCost(n);
for (int m = 1; m < n; m++) {
int sum = a[m - 1] + a[m];
if (a[m - 1] && a[m]) horizontalAll += sum;
else splitCost[m] = sum;
}
ll everyWidth = horizontalAll + a[0] + a[n - 1];
for (int w = 1; w <= n; w++) red[w] += everyWidth;
for (int w = 1; w <= n; w++) {
for (int m = w; m < n; m += w) red[w] += splitCost[m];
}
for (int w = 1; w < n; w++) {
red[w] += conv[n - 1 - w] + conv[n - 1 + w];
}
vector<ll> values(n);
ll base = 4 * total;
for (int w = 1; w <= n; w++) values[w - 1] = base - red[w];
nth_element(values.begin(), values.begin() + k - 1, values.end(), greater<ll>());
cout << values[k - 1] << '\n';
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MOD = 998244353;
const int ROOT = 3;
int modPow(ll a, ll e) {
ll r = 1;
while (e) {
if (e & 1) r = r * a % MOD;
a = a * a % MOD;
e >>= 1;
}
return (int)r;
}
void ntt(vector<int>& a, bool invert) {
int n = (int)a.size();
for (int i = 1, j = 0; i < n; i++) {
int bit = n >> 1;
for (; j & bit; bit >>= 1) j ^= bit;
j ^= bit;
if (i < j) swap(a[i], a[j]);
}
for (int len = 2; len <= n; len <<= 1) {
int wlen = modPow(ROOT, (MOD - 1) / len);
if (invert) wlen = modPow(wlen, MOD - 2);
for (int i = 0; i < n; i += len) {
ll w = 1;
for (int j = 0; j < len / 2; j++) {
int u = a[i + j];
int v = (int)(a[i + j + len / 2] * w % MOD);
int x = u + v;
if (x >= MOD) x -= MOD;
int y = u - v;
if (y < 0) y += MOD;
a[i + j] = x;
a[i + j + len / 2] = y;
w = w * wlen % MOD;
}
}
}
if (invert) {
int invN = modPow(n, MOD - 2);
for (int& x : a) x = (int)((ll)x * invN % MOD);
}
}
vector<int> convolution(vector<int> a, vector<int> b) {
int need = (int)a.size() + (int)b.size() - 1;
int n = 1;
while (n < need) n <<= 1;
a.resize(n);
b.resize(n);
ntt(a, false);
ntt(b, false);
for (int i = 0; i < n; i++) a[i] = (int)((ll)a[i] * b[i] % MOD);
ntt(a, true);
a.resize(need);
return a;
}
int main() {
setIO();
int n, k;
string s;
cin >> n >> k >> s;
vector<int> a(n), poly(n), revNonzero(n);
ll total = 0;
for (int i = 0; i < n; i++) {
a[i] = s[i] - '0';
total += a[i];
poly[i] = a[i];
revNonzero[n - 1 - i] = (a[i] > 0);
}
vector<int> conv = convolution(poly, revNonzero);
vector<ll> red(n + 2), diff(n + 3);
for (int p = 0; p < n; p++) {
if (!a[p]) continue;
diff[p + 1] += a[p];
diff[n + 1] -= a[p];
diff[n - p] += a[p];
diff[n + 1] -= a[p];
}
ll cur = 0;
for (int w = 1; w <= n; w++) {
cur += diff[w];
red[w] += cur;
}
ll horizontalAll = 0;
vector<int> splitCost(n);
for (int m = 1; m < n; m++) {
int sum = a[m - 1] + a[m];
if (a[m - 1] && a[m]) horizontalAll += sum;
else splitCost[m] = sum;
}
ll everyWidth = horizontalAll + a[0] + a[n - 1];
for (int w = 1; w <= n; w++) red[w] += everyWidth;
for (int w = 1; w <= n; w++) {
for (int m = w; m < n; m += w) red[w] += splitCost[m];
}
for (int w = 1; w < n; w++) {
red[w] += conv[n - 1 - w] + conv[n - 1 + w];
}
vector<ll> values(n);
ll base = 4 * total;
for (int w = 1; w <= n; w++) values[w - 1] = base - red[w];
nth_element(values.begin(), values.begin() + k - 1, values.end(), greater<ll>());
cout << values[k - 1] << '\n';
}