Loading [MathJax]/extensions/tex2jax.js

POI 选做

简述

突然记起来 CSP 前特别喜欢的 POI 题还有一堆没写,所以就有了这个坑。

「POI2015」TRZ

写起来还挺麻烦。

我们考虑先把条件写出来:

\[ \begin{cases} s_r^1 – s_{l – 1}^1 \neq s_r^2 – s_{l – 1}^2 \neq s_r^2 – s_{l – 1}^2 \neq s_r^1 – s_{l – 1}^1 \end{cases} \]

进行移项之后发现可以做成自身的特征:

\[ \begin{cases} s_r^1 – s_r^2 \neq s_{l – 1}^1 – s_{l – 1}^2 \\ s_r^1 – s_r^3 \neq s_{l – 1}^1 – s_{l – 1}^3 \\ s_r^2 – s_r^3 \neq s_{l – 1}^2 – s_{l – 1}^3 \end{cases} \]

我们需要找到最长的区间使得这个条件成立,那么其实这就是一个偏序问题。每一个三维的点每一维直接做成其特征即可。而这个偏序需要知道除自己以外的所有信息,所以不能像正常的偏序来搞。所以,我们来进行拼凑。考虑按 \(x\) 排序,然后把 \(y\) 插入权值线段树,最后每个节点维护两个不同的 \(z\) 的极点位置即可。有点难写。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3590.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200, INF = 0x3f3f3f3f;
int n, ans, ptot = 1;
char str[MAX_N];
struct node
{
int lson, rson, max_val[2] = {-1, -1}, min_val[2] = {INF, INF};
} nodes[MAX_N * 3];
struct package
{
int id, x, y, z;
bool operator<(const package &rhs) const { return x < rhs.x; }
} pre[MAX_N], ai[MAX_N], bi[MAX_N];
int update(int qx, int l, int r, int p, package val)
{
if (p == 0)
p = ++ptot;
if (nodes[p].min_val[0] > val.id)
{
if (nodes[p].min_val[0] != INF && bi[nodes[p].min_val[0]].id != val.z)
nodes[p].min_val[1] = nodes[p].min_val[0];
nodes[p].min_val[0] = val.id;
}
else if (nodes[p].min_val[1] > val.id && bi[nodes[p].min_val[0]].z != val.z)
nodes[p].min_val[1] = val.id;
if (nodes[p].max_val[0] < val.id)
{
if (nodes[p].max_val[0] != -1 && bi[nodes[p].max_val[0]].z != val.z)
nodes[p].max_val[1] = nodes[p].max_val[0];
nodes[p].max_val[0] = val.id;
}
else if (nodes[p].max_val[1] < val.id && bi[nodes[p].max_val[0]].z != val.z)
nodes[p].max_val[1] = val.id;
if (l == r)
return p;
int mid = (l + r) >> 1;
if (qx <= mid)
nodes[p].lson = update(qx, l, mid, nodes[p].lson, val);
else
nodes[p].rson = update(qx, mid + 1, r, nodes[p].rson, val);
return p;
}
int query(int ql, int qr, int l, int r, int p, package val)
{
if (p == 0)
return 0;
if (ql <= l && r <= qr)
{
int min_val, max_val;
if (nodes[p].min_val[0] == INF)
return 0;
min_val = (val.z == bi[nodes[p].min_val[0]].z) ? nodes[p].min_val[1] : nodes[p].min_val[0];
max_val = (val.z == bi[nodes[p].max_val[0]].z) ? nodes[p].max_val[1] : nodes[p].max_val[0];
if (min_val == INF || max_val == -1)
return 0;
return max(abs(val.id - min_val), abs(val.id - max_val));
}
int mid = (l + r) >> 1, ret = 0;
if (ql <= mid)
ret = max(ret, query(ql, qr, l, mid, nodes[p].lson, val));
if (mid < qr)
ret = max(ret, query(ql, qr, mid + 1, r, nodes[p].rson, val));
return ret;
}
int main()
{
scanf("%d%s", &n, str);
for (int i = 0, ptr = 0; i < n; i++)
{
if (str[i] != str[ptr])
ptr = i;
ans = max(ans, i - ptr + 1);
}
for (int i = 1; i <= n; i++)
{
pre[i] = pre[i - 1];
if (str[i - 1] == 'C')
pre[i].x++;
if (str[i - 1] == 'B')
pre[i].y++;
if (str[i - 1] == 'S')
pre[i].z++;
}
int lower = 0;
for (int i = 1; i <= n; i++)
{
ai[i].x = pre[i].x - pre[i].y;
ai[i].y = pre[i].x - pre[i].z;
ai[i].z = pre[i].y - pre[i].z;
lower = min(lower, min(ai[i].x, min(ai[i].y, ai[i].z)));
ai[i].id = i;
}
n++;
for (int i = 1; i <= n; i++)
ai[i].x -= lower - 1, ai[i].y -= lower - 1, ai[i].z -= lower - 1;
for (int i = 1; i <= n; i++)
bi[i] = ai[i];
bi[0] = bi[n], sort(ai + 1, ai + 1 + n);
int domain = n - lower + 1;
for (int i = 1, ptr = 1; i <= n; i++)
{
if (ai[i].x != ai[ptr].x)
ptr = i;
if (ai[i].x != ai[i + 1].x)
{
for (int j = ptr; j <= i; j++)
ans = max(ans, max(query(1, ai[j].y - 1, 1, domain, 1, ai[j]), query(ai[j].y + 1, domain, 1, domain, 1, ai[j])));
for (int j = ptr; j <= i; j++)
update(ai[j].y, 1, domain, 1, ai[j]);
}
}
printf("%d\n", ans);
return 0;
}
// P3590.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e6 + 200, INF = 0x3f3f3f3f; int n, ans, ptot = 1; char str[MAX_N]; struct node { int lson, rson, max_val[2] = {-1, -1}, min_val[2] = {INF, INF}; } nodes[MAX_N * 3]; struct package { int id, x, y, z; bool operator<(const package &rhs) const { return x < rhs.x; } } pre[MAX_N], ai[MAX_N], bi[MAX_N]; int update(int qx, int l, int r, int p, package val) { if (p == 0) p = ++ptot; if (nodes[p].min_val[0] > val.id) { if (nodes[p].min_val[0] != INF && bi[nodes[p].min_val[0]].id != val.z) nodes[p].min_val[1] = nodes[p].min_val[0]; nodes[p].min_val[0] = val.id; } else if (nodes[p].min_val[1] > val.id && bi[nodes[p].min_val[0]].z != val.z) nodes[p].min_val[1] = val.id; if (nodes[p].max_val[0] < val.id) { if (nodes[p].max_val[0] != -1 && bi[nodes[p].max_val[0]].z != val.z) nodes[p].max_val[1] = nodes[p].max_val[0]; nodes[p].max_val[0] = val.id; } else if (nodes[p].max_val[1] < val.id && bi[nodes[p].max_val[0]].z != val.z) nodes[p].max_val[1] = val.id; if (l == r) return p; int mid = (l + r) >> 1; if (qx <= mid) nodes[p].lson = update(qx, l, mid, nodes[p].lson, val); else nodes[p].rson = update(qx, mid + 1, r, nodes[p].rson, val); return p; } int query(int ql, int qr, int l, int r, int p, package val) { if (p == 0) return 0; if (ql <= l && r <= qr) { int min_val, max_val; if (nodes[p].min_val[0] == INF) return 0; min_val = (val.z == bi[nodes[p].min_val[0]].z) ? nodes[p].min_val[1] : nodes[p].min_val[0]; max_val = (val.z == bi[nodes[p].max_val[0]].z) ? nodes[p].max_val[1] : nodes[p].max_val[0]; if (min_val == INF || max_val == -1) return 0; return max(abs(val.id - min_val), abs(val.id - max_val)); } int mid = (l + r) >> 1, ret = 0; if (ql <= mid) ret = max(ret, query(ql, qr, l, mid, nodes[p].lson, val)); if (mid < qr) ret = max(ret, query(ql, qr, mid + 1, r, nodes[p].rson, val)); return ret; } int main() { scanf("%d%s", &n, str); for (int i = 0, ptr = 0; i < n; i++) { if (str[i] != str[ptr]) ptr = i; ans = max(ans, i - ptr + 1); } for (int i = 1; i <= n; i++) { pre[i] = pre[i - 1]; if (str[i - 1] == 'C') pre[i].x++; if (str[i - 1] == 'B') pre[i].y++; if (str[i - 1] == 'S') pre[i].z++; } int lower = 0; for (int i = 1; i <= n; i++) { ai[i].x = pre[i].x - pre[i].y; ai[i].y = pre[i].x - pre[i].z; ai[i].z = pre[i].y - pre[i].z; lower = min(lower, min(ai[i].x, min(ai[i].y, ai[i].z))); ai[i].id = i; } n++; for (int i = 1; i <= n; i++) ai[i].x -= lower - 1, ai[i].y -= lower - 1, ai[i].z -= lower - 1; for (int i = 1; i <= n; i++) bi[i] = ai[i]; bi[0] = bi[n], sort(ai + 1, ai + 1 + n); int domain = n - lower + 1; for (int i = 1, ptr = 1; i <= n; i++) { if (ai[i].x != ai[ptr].x) ptr = i; if (ai[i].x != ai[i + 1].x) { for (int j = ptr; j <= i; j++) ans = max(ans, max(query(1, ai[j].y - 1, 1, domain, 1, ai[j]), query(ai[j].y + 1, domain, 1, domain, 1, ai[j]))); for (int j = ptr; j <= i; j++) update(ai[j].y, 1, domain, 1, ai[j]); } } printf("%d\n", ans); return 0; }
// P3590.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e6 + 200, INF = 0x3f3f3f3f;

int n, ans, ptot = 1;
char str[MAX_N];

struct node
{
    int lson, rson, max_val[2] = {-1, -1}, min_val[2] = {INF, INF};
} nodes[MAX_N * 3];

struct package
{
    int id, x, y, z;
    bool operator<(const package &rhs) const { return x < rhs.x; }
} pre[MAX_N], ai[MAX_N], bi[MAX_N];

int update(int qx, int l, int r, int p, package val)
{
    if (p == 0)
        p = ++ptot;
    if (nodes[p].min_val[0] > val.id)
    {
        if (nodes[p].min_val[0] != INF && bi[nodes[p].min_val[0]].id != val.z)
            nodes[p].min_val[1] = nodes[p].min_val[0];
        nodes[p].min_val[0] = val.id;
    }
    else if (nodes[p].min_val[1] > val.id && bi[nodes[p].min_val[0]].z != val.z)
        nodes[p].min_val[1] = val.id;
    if (nodes[p].max_val[0] < val.id)
    {
        if (nodes[p].max_val[0] != -1 && bi[nodes[p].max_val[0]].z != val.z)
            nodes[p].max_val[1] = nodes[p].max_val[0];
        nodes[p].max_val[0] = val.id;
    }
    else if (nodes[p].max_val[1] < val.id && bi[nodes[p].max_val[0]].z != val.z)
        nodes[p].max_val[1] = val.id;
    if (l == r)
        return p;
    int mid = (l + r) >> 1;
    if (qx <= mid)
        nodes[p].lson = update(qx, l, mid, nodes[p].lson, val);
    else
        nodes[p].rson = update(qx, mid + 1, r, nodes[p].rson, val);
    return p;
}

int query(int ql, int qr, int l, int r, int p, package val)
{
    if (p == 0)
        return 0;
    if (ql <= l && r <= qr)
    {
        int min_val, max_val;
        if (nodes[p].min_val[0] == INF)
            return 0;
        min_val = (val.z == bi[nodes[p].min_val[0]].z) ? nodes[p].min_val[1] : nodes[p].min_val[0];
        max_val = (val.z == bi[nodes[p].max_val[0]].z) ? nodes[p].max_val[1] : nodes[p].max_val[0];
        if (min_val == INF || max_val == -1)
            return 0;
        return max(abs(val.id - min_val), abs(val.id - max_val));
    }
    int mid = (l + r) >> 1, ret = 0;
    if (ql <= mid)
        ret = max(ret, query(ql, qr, l, mid, nodes[p].lson, val));
    if (mid < qr)
        ret = max(ret, query(ql, qr, mid + 1, r, nodes[p].rson, val));
    return ret;
}

int main()
{
    scanf("%d%s", &n, str);
    for (int i = 0, ptr = 0; i < n; i++)
    {
        if (str[i] != str[ptr])
            ptr = i;
        ans = max(ans, i - ptr + 1);
    }
    for (int i = 1; i <= n; i++)
    {
        pre[i] = pre[i - 1];
        if (str[i - 1] == 'C')
            pre[i].x++;
        if (str[i - 1] == 'B')
            pre[i].y++;
        if (str[i - 1] == 'S')
            pre[i].z++;
    }
    int lower = 0;
    for (int i = 1; i <= n; i++)
    {
        ai[i].x = pre[i].x - pre[i].y;
        ai[i].y = pre[i].x - pre[i].z;
        ai[i].z = pre[i].y - pre[i].z;
        lower = min(lower, min(ai[i].x, min(ai[i].y, ai[i].z)));
        ai[i].id = i;
    }
    n++;
    for (int i = 1; i <= n; i++)
        ai[i].x -= lower - 1, ai[i].y -= lower - 1, ai[i].z -= lower - 1;
    for (int i = 1; i <= n; i++)
        bi[i] = ai[i];
    bi[0] = bi[n], sort(ai + 1, ai + 1 + n);
    int domain = n - lower + 1;
    for (int i = 1, ptr = 1; i <= n; i++)
    {
        if (ai[i].x != ai[ptr].x)
            ptr = i;
        if (ai[i].x != ai[i + 1].x)
        {
            for (int j = ptr; j <= i; j++)
                ans = max(ans, max(query(1, ai[j].y - 1, 1, domain, 1, ai[j]), query(ai[j].y + 1, domain, 1, domain, 1, ai[j])));
            for (int j = ptr; j <= i; j++)
                update(ai[j].y, 1, domain, 1, ai[j]);
        }
    }
    printf("%d\n", ans);
    return 0;
}

「POI2009」LYZ

之前没学过 Hall 定理,后面发现结论还算是比较显然的:对于任意的左部点集 \(U\),与之相连的极大右部点集 \(S\) 要满足 \(|U| \leq |S|\)。本题在数据范围小的时候显然可以直接二分图匹配做,但是现在的数据并不允许,并要求维护完美匹配性。首先发现最糟情况时存在一个区间 \([l, r]\) 满足:

\[ \sum_{i = l}^r X_i > (r – l + 1 + d) k \]

移项得到:

\[ \sum_{i = l}^r (X_i – k) > d \times k \]

线段树找一段这样的即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3488.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 5e5 + 200;
typedef long long ll;
int n, m, k, d;
struct node
{
ll lft, rig, sum, seg;
} nodes[MAX_N << 2];
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
void pushup(int p)
{
nodes[p].sum = nodes[lson].sum + nodes[rson].sum;
nodes[p].lft = max(nodes[lson].lft, nodes[lson].sum + nodes[rson].lft);
nodes[p].rig = max(nodes[rson].rig, nodes[rson].sum + nodes[lson].rig);
nodes[p].seg = max(nodes[lson].rig + nodes[rson].lft, max(nodes[lson].seg, nodes[rson].seg));
}
void build(int l, int r, int p)
{
if (l == r)
{
nodes[p] = node{0, 0, -k, -k};
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p);
}
void update(int qx, int l, int r, int p, int val)
{
if (l == r)
{
nodes[p].sum += val, nodes[p].seg += val;
nodes[p].lft = nodes[p].rig = max(0LL, nodes[p].sum);
return;
}
if (qx <= mid)
update(qx, l, mid, lson, val);
else
update(qx, mid + 1, r, rson, val);
pushup(p);
}
#undef mid
#undef rson
#undef lson
int main()
{
scanf("%d%d%d%d", &n, &m, &k, &d), build(1, n, 1);
for (int i = 1; i <= m; i++)
{
int xpos, val;
scanf("%d%d", &xpos, &val), update(xpos, 1, n, 1, val);
puts(nodes[1].seg <= 1LL * d * k ? "TAK" : "NIE");
}
return 0;
}
// P3488.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 5e5 + 200; typedef long long ll; int n, m, k, d; struct node { ll lft, rig, sum, seg; } nodes[MAX_N << 2]; #define lson (p << 1) #define rson ((p << 1) | 1) #define mid ((l + r) >> 1) void pushup(int p) { nodes[p].sum = nodes[lson].sum + nodes[rson].sum; nodes[p].lft = max(nodes[lson].lft, nodes[lson].sum + nodes[rson].lft); nodes[p].rig = max(nodes[rson].rig, nodes[rson].sum + nodes[lson].rig); nodes[p].seg = max(nodes[lson].rig + nodes[rson].lft, max(nodes[lson].seg, nodes[rson].seg)); } void build(int l, int r, int p) { if (l == r) { nodes[p] = node{0, 0, -k, -k}; return; } build(l, mid, lson), build(mid + 1, r, rson); pushup(p); } void update(int qx, int l, int r, int p, int val) { if (l == r) { nodes[p].sum += val, nodes[p].seg += val; nodes[p].lft = nodes[p].rig = max(0LL, nodes[p].sum); return; } if (qx <= mid) update(qx, l, mid, lson, val); else update(qx, mid + 1, r, rson, val); pushup(p); } #undef mid #undef rson #undef lson int main() { scanf("%d%d%d%d", &n, &m, &k, &d), build(1, n, 1); for (int i = 1; i <= m; i++) { int xpos, val; scanf("%d%d", &xpos, &val), update(xpos, 1, n, 1, val); puts(nodes[1].seg <= 1LL * d * k ? "TAK" : "NIE"); } return 0; }
// P3488.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 5e5 + 200;

typedef long long ll;

int n, m, k, d;

struct node
{
    ll lft, rig, sum, seg;
} nodes[MAX_N << 2];

#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)

void pushup(int p)
{
    nodes[p].sum = nodes[lson].sum + nodes[rson].sum;
    nodes[p].lft = max(nodes[lson].lft, nodes[lson].sum + nodes[rson].lft);
    nodes[p].rig = max(nodes[rson].rig, nodes[rson].sum + nodes[lson].rig);
    nodes[p].seg = max(nodes[lson].rig + nodes[rson].lft, max(nodes[lson].seg, nodes[rson].seg));
}

void build(int l, int r, int p)
{
    if (l == r)
    {
        nodes[p] = node{0, 0, -k, -k};
        return;
    }
    build(l, mid, lson), build(mid + 1, r, rson);
    pushup(p);
}

void update(int qx, int l, int r, int p, int val)
{
    if (l == r)
    {
        nodes[p].sum += val, nodes[p].seg += val;
        nodes[p].lft = nodes[p].rig = max(0LL, nodes[p].sum);
        return;
    }
    if (qx <= mid)
        update(qx, l, mid, lson, val);
    else
        update(qx, mid + 1, r, rson, val);
    pushup(p);
}

#undef mid
#undef rson
#undef lson

int main()
{
    scanf("%d%d%d%d", &n, &m, &k, &d), build(1, n, 1);
    for (int i = 1; i <= m; i++)
    {
        int xpos, val;
        scanf("%d%d", &xpos, &val), update(xpos, 1, n, 1, val);
        puts(nodes[1].seg <= 1LL * d * k ? "TAK" : "NIE");
    }
    return 0;
}

「POI2014」KAR

想起在纪中做过的一道 A 组 SB 题,跟这个比较一致。发现区间之间可以直接维护,那么就上个线段树就好了。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3569.cpp
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 4e5 + 200;
int n, ai[MAX_N][2], q;
bool nodes[MAX_N << 2][2][2];
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p, int l, int r)
{
nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
for (register int a = 0; a < 2; a++)
for (register int b = 0; b < 2; b++)
for (register int c = 0; c < 2; c++)
for (register int d = 0; d < 2; d++)
nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
}
inline void update(int qx, int l, int r, int p)
{
if (l == r)
return;
if (qx <= mid)
update(qx, l, mid, lson);
else
update(qx, mid + 1, r, rson);
pushup(p, l, r);
}
inline void build(int l, int r, int p)
{
if (l == r)
{
nodes[p][0][0] = nodes[p][1][1] = true;
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p, l, r);
}
#undef mid
#undef rson
#undef lson
int main()
{
n = read();
for (register int i = 1; i <= n; i++)
ai[i][0] = read(), ai[i][1] = read();
q = read(), build(1, n, 1);
while (q--)
{
int x = read(), y = read();
swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
update(x, 1, n, 1), update(y, 1, n, 1);
puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
}
return 0;
}
// P3569.cpp #pragma GCC optimize("Ofast") #include <bits/stdc++.h> using namespace std; const int MAX_N = 4e5 + 200; int n, ai[MAX_N][2], q; bool nodes[MAX_N << 2][2][2]; inline char nc() { static char buf[100000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++; } int read() { int x = 0, f = 1; char ch = nc(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = nc(); } while (isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = nc(); return x * f; } #define lson (p << 1) #define rson ((p << 1) | 1) #define mid ((l + r) >> 1) inline void pushup(int p, int l, int r) { nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false; for (register int a = 0; a < 2; a++) for (register int b = 0; b < 2; b++) for (register int c = 0; c < 2; c++) for (register int d = 0; d < 2; d++) nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b]; } inline void update(int qx, int l, int r, int p) { if (l == r) return; if (qx <= mid) update(qx, l, mid, lson); else update(qx, mid + 1, r, rson); pushup(p, l, r); } inline void build(int l, int r, int p) { if (l == r) { nodes[p][0][0] = nodes[p][1][1] = true; return; } build(l, mid, lson), build(mid + 1, r, rson); pushup(p, l, r); } #undef mid #undef rson #undef lson int main() { n = read(); for (register int i = 1; i <= n; i++) ai[i][0] = read(), ai[i][1] = read(); q = read(), build(1, n, 1); while (q--) { int x = read(), y = read(); swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]); update(x, 1, n, 1), update(y, 1, n, 1); puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE"); } return 0; }
// P3569.cpp
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 4e5 + 200;

int n, ai[MAX_N][2], q;
bool nodes[MAX_N << 2][2][2];

inline char nc()
{
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

int read()
{
    int x = 0, f = 1;
    char ch = nc();
    while (!isdigit(ch))
    {
        if (ch == '-')
            f = -1;
        ch = nc();
    }
    while (isdigit(ch))
        x = (x << 3) + (x << 1) + ch - '0', ch = nc();
    return x * f;
}

#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)

inline void pushup(int p, int l, int r)
{
    nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
    for (register int a = 0; a < 2; a++)
        for (register int b = 0; b < 2; b++)
            for (register int c = 0; c < 2; c++)
                for (register int d = 0; d < 2; d++)
                    nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
}

inline void update(int qx, int l, int r, int p)
{
    if (l == r)
        return;
    if (qx <= mid)
        update(qx, l, mid, lson);
    else
        update(qx, mid + 1, r, rson);
    pushup(p, l, r);
}

inline void build(int l, int r, int p)
{
    if (l == r)
    {
        nodes[p][0][0] = nodes[p][1][1] = true;
        return;
    }
    build(l, mid, lson), build(mid + 1, r, rson);
    pushup(p, l, r);
}

#undef mid
#undef rson
#undef lson

int main()
{
    n = read();
    for (register int i = 1; i <= n; i++)
        ai[i][0] = read(), ai[i][1] = read();
    q = read(), build(1, n, 1);
    while (q--)
    {
        int x = read(), y = read();
        swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
        update(x, 1, n, 1), update(y, 1, n, 1);
        puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
    }
    return 0;
}

「POI2014」KLO

我们考虑相间而放,用一个堆以大小为关键字来维护可选项。注意的是,我们尽量把和末尾颜色相同的 block 放前。每次选出最大的块、或者是次大的块放置,然后再 check 即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3569.cpp
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 4e5 + 200;
int n, ai[MAX_N][2], q;
bool nodes[MAX_N << 2][2][2];
inline char nc()
{
static char buf[100000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
inline void pushup(int p, int l, int r)
{
nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
for (register int a = 0; a < 2; a++)
for (register int b = 0; b < 2; b++)
for (register int c = 0; c < 2; c++)
for (register int d = 0; d < 2; d++)
nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
}
inline void update(int qx, int l, int r, int p)
{
if (l == r)
return;
if (qx <= mid)
update(qx, l, mid, lson);
else
update(qx, mid + 1, r, rson);
pushup(p, l, r);
}
inline void build(int l, int r, int p)
{
if (l == r)
{
nodes[p][0][0] = nodes[p][1][1] = true;
return;
}
build(l, mid, lson), build(mid + 1, r, rson);
pushup(p, l, r);
}
#undef mid
#undef rson
#undef lson
int main()
{
n = read();
for (register int i = 1; i <= n; i++)
ai[i][0] = read(), ai[i][1] = read();
q = read(), build(1, n, 1);
while (q--)
{
int x = read(), y = read();
swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
update(x, 1, n, 1), update(y, 1, n, 1);
puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
}
return 0;
}
// P3569.cpp #pragma GCC optimize("Ofast") #include <bits/stdc++.h> using namespace std; const int MAX_N = 4e5 + 200; int n, ai[MAX_N][2], q; bool nodes[MAX_N << 2][2][2]; inline char nc() { static char buf[100000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++; } int read() { int x = 0, f = 1; char ch = nc(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = nc(); } while (isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = nc(); return x * f; } #define lson (p << 1) #define rson ((p << 1) | 1) #define mid ((l + r) >> 1) inline void pushup(int p, int l, int r) { nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false; for (register int a = 0; a < 2; a++) for (register int b = 0; b < 2; b++) for (register int c = 0; c < 2; c++) for (register int d = 0; d < 2; d++) nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b]; } inline void update(int qx, int l, int r, int p) { if (l == r) return; if (qx <= mid) update(qx, l, mid, lson); else update(qx, mid + 1, r, rson); pushup(p, l, r); } inline void build(int l, int r, int p) { if (l == r) { nodes[p][0][0] = nodes[p][1][1] = true; return; } build(l, mid, lson), build(mid + 1, r, rson); pushup(p, l, r); } #undef mid #undef rson #undef lson int main() { n = read(); for (register int i = 1; i <= n; i++) ai[i][0] = read(), ai[i][1] = read(); q = read(), build(1, n, 1); while (q--) { int x = read(), y = read(); swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]); update(x, 1, n, 1), update(y, 1, n, 1); puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE"); } return 0; }
// P3569.cpp
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 4e5 + 200;

int n, ai[MAX_N][2], q;
bool nodes[MAX_N << 2][2][2];

inline char nc()
{
    static char buf[100000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

int read()
{
    int x = 0, f = 1;
    char ch = nc();
    while (!isdigit(ch))
    {
        if (ch == '-')
            f = -1;
        ch = nc();
    }
    while (isdigit(ch))
        x = (x << 3) + (x << 1) + ch - '0', ch = nc();
    return x * f;
}

#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)

inline void pushup(int p, int l, int r)
{
    nodes[p][0][0] = nodes[p][1][0] = nodes[p][0][1] = nodes[p][1][1] = false;
    for (register int a = 0; a < 2; a++)
        for (register int b = 0; b < 2; b++)
            for (register int c = 0; c < 2; c++)
                for (register int d = 0; d < 2; d++)
                    nodes[p][a][d] |= nodes[lson][a][c] && nodes[rson][b][d] && ai[mid][c] <= ai[mid + 1][b];
}

inline void update(int qx, int l, int r, int p)
{
    if (l == r)
        return;
    if (qx <= mid)
        update(qx, l, mid, lson);
    else
        update(qx, mid + 1, r, rson);
    pushup(p, l, r);
}

inline void build(int l, int r, int p)
{
    if (l == r)
    {
        nodes[p][0][0] = nodes[p][1][1] = true;
        return;
    }
    build(l, mid, lson), build(mid + 1, r, rson);
    pushup(p, l, r);
}

#undef mid
#undef rson
#undef lson

int main()
{
    n = read();
    for (register int i = 1; i <= n; i++)
        ai[i][0] = read(), ai[i][1] = read();
    q = read(), build(1, n, 1);
    while (q--)
    {
        int x = read(), y = read();
        swap(ai[x][0], ai[y][0]), swap(ai[x][1], ai[y][1]);
        update(x, 1, n, 1), update(y, 1, n, 1);
        puts(nodes[1][0][0] || nodes[1][0][1] || nodes[1][1][0] || nodes[1][1][1] ? "TAK" : "NIE");
    }
    return 0;
}

「POI2010」Monotonicity

首先我们可以把符号序列给倍长出来,然后再考虑用子序列匹配那一套进行 DP。而这里只需要单维,也就是说我们并不记录子序列的长度,因为可以注意到最长的答案中间切掉,也是满足最优子结构的(证明),所以可以不用记录,搞个树状数组就完事了。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// BZ2090.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 1e6 + 200, MAX_M = 5e6 + 200;
int n, m, ai[MAX_N], nodes[3][MAX_M], dp[MAX_N];
char str[MAX_N];
inline int lowbit(int x) { return x & (-x); }
void update(int idx, int x, int d)
{
for (; x < MAX_M; x += lowbit(x))
nodes[idx][x] = max(nodes[idx][x], d);
}
int query(int idx, int x, int ret = 0)
{
for (; x; x -= lowbit(x))
ret = max(ret, nodes[idx][x]);
return ret;
}
int main()
{
char tmp[2];
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &ai[i]);
for (int i = 1; i <= m; i++)
scanf("%s", tmp), str[i] = tmp[0];
for (int i = m + 1; i <= n; i++)
str[i] = str[(i - 1) % m + 1];
int ans = 0;
for (int i = 1; i <= n; i++)
{
dp[i] = max(nodes[2][ai[i]], max(query(0, ai[i] - 1), query(1, MAX_M - ai[i]))) + 1;
ans = max(ans, dp[i]);
if (str[dp[i]] == '=')
nodes[2][ai[i]] = max(nodes[2][ai[i]], dp[i]);
else if (str[dp[i]] == '<')
update(0, ai[i], dp[i]);
else
update(1, MAX_M - ai[i] + 1, dp[i]);
}
printf("%d\n", ans);
return 0;
}
// BZ2090.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 1e6 + 200, MAX_M = 5e6 + 200; int n, m, ai[MAX_N], nodes[3][MAX_M], dp[MAX_N]; char str[MAX_N]; inline int lowbit(int x) { return x & (-x); } void update(int idx, int x, int d) { for (; x < MAX_M; x += lowbit(x)) nodes[idx][x] = max(nodes[idx][x], d); } int query(int idx, int x, int ret = 0) { for (; x; x -= lowbit(x)) ret = max(ret, nodes[idx][x]); return ret; } int main() { char tmp[2]; scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &ai[i]); for (int i = 1; i <= m; i++) scanf("%s", tmp), str[i] = tmp[0]; for (int i = m + 1; i <= n; i++) str[i] = str[(i - 1) % m + 1]; int ans = 0; for (int i = 1; i <= n; i++) { dp[i] = max(nodes[2][ai[i]], max(query(0, ai[i] - 1), query(1, MAX_M - ai[i]))) + 1; ans = max(ans, dp[i]); if (str[dp[i]] == '=') nodes[2][ai[i]] = max(nodes[2][ai[i]], dp[i]); else if (str[dp[i]] == '<') update(0, ai[i], dp[i]); else update(1, MAX_M - ai[i] + 1, dp[i]); } printf("%d\n", ans); return 0; }
// BZ2090.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e6 + 200, MAX_M = 5e6 + 200;

int n, m, ai[MAX_N], nodes[3][MAX_M], dp[MAX_N];
char str[MAX_N];

inline int lowbit(int x) { return x & (-x); }

void update(int idx, int x, int d)
{
    for (; x < MAX_M; x += lowbit(x))
        nodes[idx][x] = max(nodes[idx][x], d);
}

int query(int idx, int x, int ret = 0)
{
    for (; x; x -= lowbit(x))
        ret = max(ret, nodes[idx][x]);
    return ret;
}

int main()
{
    char tmp[2];
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &ai[i]);
    for (int i = 1; i <= m; i++)
        scanf("%s", tmp), str[i] = tmp[0];
    for (int i = m + 1; i <= n; i++)
        str[i] = str[(i - 1) % m + 1];
    int ans = 0;
    for (int i = 1; i <= n; i++)
    {
        dp[i] = max(nodes[2][ai[i]], max(query(0, ai[i] - 1), query(1, MAX_M - ai[i]))) + 1;
        ans = max(ans, dp[i]);
        if (str[dp[i]] == '=')
            nodes[2][ai[i]] = max(nodes[2][ai[i]], dp[i]);
        else if (str[dp[i]] == '<')
            update(0, ai[i], dp[i]);
        else
            update(1, MAX_M - ai[i] + 1, dp[i]);
    }
    printf("%d\n", ans);
    return 0;
}

「POI2005」DWA-Two Parties

这道题就很骚了。

首先有个结论,就是一定能找出一个划分方案,使得某个集合中所有的点都连上了偶数条边,且是最优解。知道这个,我们可以尝试给每个点表一个状态 \(x_i\),代表其集合 ID(0/1)。这样我们可以搞成一个异或方程组,然后高斯消元得到一个方案即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3429.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 220;
int n, deg[MAX_N], mat[MAX_N][MAX_N];
int main()
{
scanf("%d", &n);
for (int i = 1, tot, v; i <= n; i++)
{
scanf("%d", &tot);
while (tot--)
scanf("%d", &v), mat[i][v] = 1, deg[i]++;
if (deg[i] & 1)
mat[i][i] = mat[i][n + 1] = 1;
}
for (int i = 1; i <= n; i++)
{
int key = i;
for (int j = i + 1; j <= n; j++)
if (mat[j][i] != 0)
{
key = j;
break;
}
if (key != i)
for (int j = i; j <= n + 1; j++)
swap(mat[i][j], mat[key][j]);
for (int j = i + 1; j <= n; j++)
if (mat[j][i] == 1)
for (int k = i; k <= n + 1; k++)
mat[j][k] ^= mat[i][k];
}
mat[n][n] = 1;
// reverse;
for (int i = n - 1; i >= 1; i--)
{
for (int j = i + 1; j <= n; j++)
if (mat[i][j] != 0)
for (int k = j; k <= n + 1; k++)
mat[i][k] ^= mat[j][k];
mat[i][i] = 1;
}
int tot = 0;
for (int i = 1; i <= n; i++)
tot += mat[i][n + 1];
printf("%d\n", tot);
for (int i = 1; i <= n; i++)
if (mat[i][n + 1])
printf("%d ", i);
puts("");
return 0;
}
// P3429.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 220; int n, deg[MAX_N], mat[MAX_N][MAX_N]; int main() { scanf("%d", &n); for (int i = 1, tot, v; i <= n; i++) { scanf("%d", &tot); while (tot--) scanf("%d", &v), mat[i][v] = 1, deg[i]++; if (deg[i] & 1) mat[i][i] = mat[i][n + 1] = 1; } for (int i = 1; i <= n; i++) { int key = i; for (int j = i + 1; j <= n; j++) if (mat[j][i] != 0) { key = j; break; } if (key != i) for (int j = i; j <= n + 1; j++) swap(mat[i][j], mat[key][j]); for (int j = i + 1; j <= n; j++) if (mat[j][i] == 1) for (int k = i; k <= n + 1; k++) mat[j][k] ^= mat[i][k]; } mat[n][n] = 1; // reverse; for (int i = n - 1; i >= 1; i--) { for (int j = i + 1; j <= n; j++) if (mat[i][j] != 0) for (int k = j; k <= n + 1; k++) mat[i][k] ^= mat[j][k]; mat[i][i] = 1; } int tot = 0; for (int i = 1; i <= n; i++) tot += mat[i][n + 1]; printf("%d\n", tot); for (int i = 1; i <= n; i++) if (mat[i][n + 1]) printf("%d ", i); puts(""); return 0; }
// P3429.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 220;

int n, deg[MAX_N], mat[MAX_N][MAX_N];

int main()
{
    scanf("%d", &n);
    for (int i = 1, tot, v; i <= n; i++)
    {
        scanf("%d", &tot);
        while (tot--)
            scanf("%d", &v), mat[i][v] = 1, deg[i]++;
        if (deg[i] & 1)
            mat[i][i] = mat[i][n + 1] = 1;
    }
    for (int i = 1; i <= n; i++)
    {
        int key = i;
        for (int j = i + 1; j <= n; j++)
            if (mat[j][i] != 0)
            {
                key = j;
                break;
            }
        if (key != i)
            for (int j = i; j <= n + 1; j++)
                swap(mat[i][j], mat[key][j]);
        for (int j = i + 1; j <= n; j++)
            if (mat[j][i] == 1)
                for (int k = i; k <= n + 1; k++)
                    mat[j][k] ^= mat[i][k];
    }
    mat[n][n] = 1;
    // reverse;
    for (int i = n - 1; i >= 1; i--)
    {
        for (int j = i + 1; j <= n; j++)
            if (mat[i][j] != 0)
                for (int k = j; k <= n + 1; k++)
                    mat[i][k] ^= mat[j][k];
        mat[i][i] = 1;
    }
    int tot = 0;
    for (int i = 1; i <= n; i++)
        tot += mat[i][n + 1];
    printf("%d\n", tot);
    for (int i = 1; i <= n; i++)
        if (mat[i][n + 1])
            printf("%d ", i);
    puts("");
    return 0;
}

「POI2012」STU-Well

大概思路:首先二分那个差值,然后我们再来算每个位置归零的代价,再找最小的位置即可。

那么我们如何快速计算每个位置归零的代价呢?首先我们可以计算让全局合法的最小代价,方式是正反各扫一遍,保证 \(|a_i – a_{i + 1}| \leq mid\)。枚举 \(k\) 时,我们可以分左右来算贡献。以左侧为例,找到一个位置 \(a_{L} > (k – L)mid\),那么 \([L, i – 1]\) 这一部分的和减去等差数列之和就是部分贡献了。我想了一会为什么这样是对的,发现:如果 \(a_{L} > (k – L)mid\),且即使这段区间不是等差的,那么这段区间和减去等差数列之和,「多扣」的部分会从 \(a_L\) 上扣除。右侧原理一致。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3534.cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX_N = 1e6 + 200;
int n;
ll m, xi[MAX_N], ai[MAX_N], pre[MAX_N], prefix[MAX_N], suffix[MAX_N];
int check(int mid)
{
ai[1] = xi[1];
for (int i = 2; i <= n; i++)
ai[i] = min(ai[i - 1] + mid, xi[i]);
for (int i = n - 1; i >= 1; i--)
ai[i] = min(ai[i + 1] + mid, ai[i]);
ll acc = 0;
for (int i = 1; i <= n; i++)
acc += xi[i] - ai[i], pre[i] = pre[i - 1] + ai[i];
if (acc > m)
return 0;
for (int i = 1, ptr = 1; i <= n; i++)
{
while (ptr < i && ai[ptr] <= 1LL * (i - ptr) * mid)
ptr++;
prefix[i] = pre[i - 1] - pre[ptr - 1] - 1LL * (i - ptr) * (i - ptr + 1) / 2 * mid;
}
for (int i = n, ptr = n; i >= 1; i--)
{
while (ptr > i && ai[ptr] <= 1LL * (ptr - i) * mid)
ptr--;
suffix[i] = pre[ptr] - pre[i] - 1LL * (ptr - i) * (ptr - i + 1) / 2 * mid;
}
for (int i = 1; i <= n; i++)
if (prefix[i] + suffix[i] + acc + ai[i] <= m)
return i;
return 0;
}
int main()
{
scanf("%d%lld", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%lld", &xi[i]);
int l = 0, r = 1e9, res = 0;
while (l <= r)
{
int mid = (l + r) >> 1;
if (check(mid))
r = mid - 1, res = mid;
else
l = mid + 1;
}
printf("%d %d\n", check(res), res);
return 0;
}
// P3534.cpp #include <bits/stdc++.h> using namespace std; typedef long long ll; const int MAX_N = 1e6 + 200; int n; ll m, xi[MAX_N], ai[MAX_N], pre[MAX_N], prefix[MAX_N], suffix[MAX_N]; int check(int mid) { ai[1] = xi[1]; for (int i = 2; i <= n; i++) ai[i] = min(ai[i - 1] + mid, xi[i]); for (int i = n - 1; i >= 1; i--) ai[i] = min(ai[i + 1] + mid, ai[i]); ll acc = 0; for (int i = 1; i <= n; i++) acc += xi[i] - ai[i], pre[i] = pre[i - 1] + ai[i]; if (acc > m) return 0; for (int i = 1, ptr = 1; i <= n; i++) { while (ptr < i && ai[ptr] <= 1LL * (i - ptr) * mid) ptr++; prefix[i] = pre[i - 1] - pre[ptr - 1] - 1LL * (i - ptr) * (i - ptr + 1) / 2 * mid; } for (int i = n, ptr = n; i >= 1; i--) { while (ptr > i && ai[ptr] <= 1LL * (ptr - i) * mid) ptr--; suffix[i] = pre[ptr] - pre[i] - 1LL * (ptr - i) * (ptr - i + 1) / 2 * mid; } for (int i = 1; i <= n; i++) if (prefix[i] + suffix[i] + acc + ai[i] <= m) return i; return 0; } int main() { scanf("%d%lld", &n, &m); for (int i = 1; i <= n; i++) scanf("%lld", &xi[i]); int l = 0, r = 1e9, res = 0; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) r = mid - 1, res = mid; else l = mid + 1; } printf("%d %d\n", check(res), res); return 0; }
// P3534.cpp
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int MAX_N = 1e6 + 200;

int n;
ll m, xi[MAX_N], ai[MAX_N], pre[MAX_N], prefix[MAX_N], suffix[MAX_N];

int check(int mid)
{
    ai[1] = xi[1];
    for (int i = 2; i <= n; i++)
        ai[i] = min(ai[i - 1] + mid, xi[i]);
    for (int i = n - 1; i >= 1; i--)
        ai[i] = min(ai[i + 1] + mid, ai[i]);
    ll acc = 0;
    for (int i = 1; i <= n; i++)
        acc += xi[i] - ai[i], pre[i] = pre[i - 1] + ai[i];
    if (acc > m)
        return 0;
    for (int i = 1, ptr = 1; i <= n; i++)
    {
        while (ptr < i && ai[ptr] <= 1LL * (i - ptr) * mid)
            ptr++;
        prefix[i] = pre[i - 1] - pre[ptr - 1] - 1LL * (i - ptr) * (i - ptr + 1) / 2 * mid;
    }
    for (int i = n, ptr = n; i >= 1; i--)
    {
        while (ptr > i && ai[ptr] <= 1LL * (ptr - i) * mid)
            ptr--;
        suffix[i] = pre[ptr] - pre[i] - 1LL * (ptr - i) * (ptr - i + 1) / 2 * mid;
    }
    for (int i = 1; i <= n; i++)
        if (prefix[i] + suffix[i] + acc + ai[i] <= m)
            return i;
    return 0;
}

int main()
{
    scanf("%d%lld", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &xi[i]);
    int l = 0, r = 1e9, res = 0;
    while (l <= r)
    {
        int mid = (l + r) >> 1;
        if (check(mid))
            r = mid - 1, res = mid;
        else
            l = mid + 1;
    }
    printf("%d %d\n", check(res), res);
    return 0;
}

「POI2014」PAN-Solar Panels

题目大概就是要求你在二维平面上,找到一个最大的 \(d\) 使得刚好 \(x = kd, y = kd\) 在这个矩形内有交点。发现有交点的条件是:

\[ \lfloor \frac{smax}{d} \rfloor – \lfloor \frac{smin – 1}{d} \rfloor > 0 \\ \lfloor \frac{wmax}{d} \rfloor – \lfloor \frac{wmin – 1}{d} \rfloor > 0 \]

那可以直接搞搞整除分块,每次取右端点做答案即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3579.cpp
#include <bits/stdc++.h>
using namespace std;
int T, smin, smax, wmin, wmax;
inline char nc()
{
static char buf[1000000], *p1 = buf, *p2 = buf;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}
int read()
{
int x = 0, f = 1;
char ch = nc();
while (!isdigit(ch))
{
if (ch == '-')
f = -1;
ch = nc();
}
while (isdigit(ch))
x = (x << 3) + (x << 1) + ch - '0', ch = nc();
return x * f;
}
int main()
{
scanf("%d", &T);
while (T--)
{
smin = read(), smax = read(), wmin = read(), wmax = read();
smin--, wmin--;
int ans = 0;
for (int d = 1, gx; d <= min(smax, wmax); d = gx + 1)
{
gx = min({smax / (smax / d), wmax / (wmax / d)});
if (int(smin / d) != 0)
gx = min(gx, smin / (smin / d));
if (int(wmin / d) != 0)
gx = min(gx, wmin / (wmin / d));
if ((smax / d) - (smin / d) > 0 && (wmax / d) - (wmin / d) > 0)
ans = gx;
}
printf("%d\n", ans);
}
return 0;
}
// P3579.cpp #include <bits/stdc++.h> using namespace std; int T, smin, smax, wmin, wmax; inline char nc() { static char buf[1000000], *p1 = buf, *p2 = buf; return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++; } int read() { int x = 0, f = 1; char ch = nc(); while (!isdigit(ch)) { if (ch == '-') f = -1; ch = nc(); } while (isdigit(ch)) x = (x << 3) + (x << 1) + ch - '0', ch = nc(); return x * f; } int main() { scanf("%d", &T); while (T--) { smin = read(), smax = read(), wmin = read(), wmax = read(); smin--, wmin--; int ans = 0; for (int d = 1, gx; d <= min(smax, wmax); d = gx + 1) { gx = min({smax / (smax / d), wmax / (wmax / d)}); if (int(smin / d) != 0) gx = min(gx, smin / (smin / d)); if (int(wmin / d) != 0) gx = min(gx, wmin / (wmin / d)); if ((smax / d) - (smin / d) > 0 && (wmax / d) - (wmin / d) > 0) ans = gx; } printf("%d\n", ans); } return 0; }
// P3579.cpp
#include <bits/stdc++.h>

using namespace std;

int T, smin, smax, wmin, wmax;

inline char nc()
{
    static char buf[1000000], *p1 = buf, *p2 = buf;
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
}

int read()
{
    int x = 0, f = 1;
    char ch = nc();
    while (!isdigit(ch))
    {
        if (ch == '-')
            f = -1;
        ch = nc();
    }
    while (isdigit(ch))
        x = (x << 3) + (x << 1) + ch - '0', ch = nc();
    return x * f;
}

int main()
{
    scanf("%d", &T);
    while (T--)
    {
        smin = read(), smax = read(), wmin = read(), wmax = read();
        smin--, wmin--;
        int ans = 0;
        for (int d = 1, gx; d <= min(smax, wmax); d = gx + 1)
        {
            gx = min({smax / (smax / d), wmax / (wmax / d)});
            if (int(smin / d) != 0)
                gx = min(gx, smin / (smin / d));
            if (int(wmin / d) != 0)
                gx = min(gx, wmin / (wmin / d));
            if ((smax / d) - (smin / d) > 0 && (wmax / d) - (wmin / d) > 0)
                ans = gx;
        }
        printf("%d\n", ans);
    }
    return 0;
}

「POI2015」PUS

经典的线段树优化建图,暴力拆成 \(k + 1\) 个区间之后跑 DAG DP 即可。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
// P3588.cpp
#include <bits/stdc++.h>
using namespace std;
const int MAX_N = 6e5 + 200, MAX_E = 8e6 + 200;
int n, s, m, dp[MAX_N], head[MAX_N], current, sidx[MAX_N], ptot, deg[MAX_N], topoidx[MAX_N], topotot;
bool isFixed[MAX_N];
struct edge
{
int to, nxt, weight;
} edges[MAX_E];
void addpath(int src, int dst, int weight)
{
edges[current].to = dst, edges[current].nxt = head[src];
edges[current].weight = weight, head[src] = current++, deg[dst]++;
}
#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)
void build(int l, int r, int p)
{
ptot = max(ptot, p);
if (l == r)
return (void)(sidx[l] = p);
addpath(p, lson, 0), addpath(p, rson, 0);
build(l, mid, lson), build(mid + 1, r, rson);
}
void update(int ql, int qr, int l, int r, int p, int src)
{
if (ql > qr)
return;
if (ql <= l && r <= qr)
return (void)(addpath(src, p, 0));
if (ql <= mid)
update(ql, qr, l, mid, lson, src);
if (mid < qr)
update(ql, qr, mid + 1, r, rson, src);
}
#undef mid
#undef rson
#undef lson
int main()
{
memset(head, -1, sizeof(head));
scanf("%d%d%d", &n, &s, &m), build(1, n, 1);
for (int i = 1; i <= n; i++)
dp[sidx[i]] = 1;
for (int i = 1, p, d; i <= s; i++)
scanf("%d%d", &p, &d), dp[sidx[p]] = d, isFixed[sidx[p]] = true;
while (m--)
{
int l, r, k, cpt, last = l - 1;
scanf("%d%d%d", &l, &r, &k), cpt = ++ptot, last = l - 1;
for (int i = 1, pt; i <= k; i++)
scanf("%d", &pt), addpath(sidx[pt], cpt, 1), update(last + 1, pt - 1, 1, n, 1, cpt), last = pt;
update(last + 1, r, 1, n, 1, cpt);
}
queue<int> q;
for (int i = 1; i <= ptot; i++)
if (deg[i] == 0)
q.push(i);
while (!q.empty())
{
int u = q.front();
q.pop(), topoidx[++topotot] = u;
for (int i = head[u]; i != -1; i = edges[i].nxt)
if (--deg[edges[i].to] == 0)
q.push(edges[i].to);
}
for (int i = 1; i <= ptot; i++)
if (deg[i] != 0)
puts("NIE"), exit(0);
for (int id = ptot; id >= 1; id--)
{
int u = topoidx[id], max_val = 1;
for (int i = head[u]; i != -1; i = edges[i].nxt)
max_val = max(max_val, dp[edges[i].to] + edges[i].weight);
if (isFixed[u] && max_val > dp[u])
puts("NIE"), exit(0);
else if (!isFixed[u])
dp[u] = max_val;
}
for (int i = 1; i <= n; i++)
if (dp[sidx[i]] > 1e9 || dp[sidx[i]] < 1)
puts("NIE"), exit(0);
puts("TAK");
for (int i = 1; i <= n; i++)
printf("%d%c", dp[sidx[i]], " \n"[i == n]);
return 0;
}
// P3588.cpp #include <bits/stdc++.h> using namespace std; const int MAX_N = 6e5 + 200, MAX_E = 8e6 + 200; int n, s, m, dp[MAX_N], head[MAX_N], current, sidx[MAX_N], ptot, deg[MAX_N], topoidx[MAX_N], topotot; bool isFixed[MAX_N]; struct edge { int to, nxt, weight; } edges[MAX_E]; void addpath(int src, int dst, int weight) { edges[current].to = dst, edges[current].nxt = head[src]; edges[current].weight = weight, head[src] = current++, deg[dst]++; } #define lson (p << 1) #define rson ((p << 1) | 1) #define mid ((l + r) >> 1) void build(int l, int r, int p) { ptot = max(ptot, p); if (l == r) return (void)(sidx[l] = p); addpath(p, lson, 0), addpath(p, rson, 0); build(l, mid, lson), build(mid + 1, r, rson); } void update(int ql, int qr, int l, int r, int p, int src) { if (ql > qr) return; if (ql <= l && r <= qr) return (void)(addpath(src, p, 0)); if (ql <= mid) update(ql, qr, l, mid, lson, src); if (mid < qr) update(ql, qr, mid + 1, r, rson, src); } #undef mid #undef rson #undef lson int main() { memset(head, -1, sizeof(head)); scanf("%d%d%d", &n, &s, &m), build(1, n, 1); for (int i = 1; i <= n; i++) dp[sidx[i]] = 1; for (int i = 1, p, d; i <= s; i++) scanf("%d%d", &p, &d), dp[sidx[p]] = d, isFixed[sidx[p]] = true; while (m--) { int l, r, k, cpt, last = l - 1; scanf("%d%d%d", &l, &r, &k), cpt = ++ptot, last = l - 1; for (int i = 1, pt; i <= k; i++) scanf("%d", &pt), addpath(sidx[pt], cpt, 1), update(last + 1, pt - 1, 1, n, 1, cpt), last = pt; update(last + 1, r, 1, n, 1, cpt); } queue<int> q; for (int i = 1; i <= ptot; i++) if (deg[i] == 0) q.push(i); while (!q.empty()) { int u = q.front(); q.pop(), topoidx[++topotot] = u; for (int i = head[u]; i != -1; i = edges[i].nxt) if (--deg[edges[i].to] == 0) q.push(edges[i].to); } for (int i = 1; i <= ptot; i++) if (deg[i] != 0) puts("NIE"), exit(0); for (int id = ptot; id >= 1; id--) { int u = topoidx[id], max_val = 1; for (int i = head[u]; i != -1; i = edges[i].nxt) max_val = max(max_val, dp[edges[i].to] + edges[i].weight); if (isFixed[u] && max_val > dp[u]) puts("NIE"), exit(0); else if (!isFixed[u]) dp[u] = max_val; } for (int i = 1; i <= n; i++) if (dp[sidx[i]] > 1e9 || dp[sidx[i]] < 1) puts("NIE"), exit(0); puts("TAK"); for (int i = 1; i <= n; i++) printf("%d%c", dp[sidx[i]], " \n"[i == n]); return 0; }
// P3588.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 6e5 + 200, MAX_E = 8e6 + 200;

int n, s, m, dp[MAX_N], head[MAX_N], current, sidx[MAX_N], ptot, deg[MAX_N], topoidx[MAX_N], topotot;
bool isFixed[MAX_N];

struct edge
{
    int to, nxt, weight;
} edges[MAX_E];

void addpath(int src, int dst, int weight)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    edges[current].weight = weight, head[src] = current++, deg[dst]++;
}

#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)

void build(int l, int r, int p)
{
    ptot = max(ptot, p);
    if (l == r)
        return (void)(sidx[l] = p);
    addpath(p, lson, 0), addpath(p, rson, 0);
    build(l, mid, lson), build(mid + 1, r, rson);
}

void update(int ql, int qr, int l, int r, int p, int src)
{
    if (ql > qr)
        return;
    if (ql <= l && r <= qr)
        return (void)(addpath(src, p, 0));
    if (ql <= mid)
        update(ql, qr, l, mid, lson, src);
    if (mid < qr)
        update(ql, qr, mid + 1, r, rson, src);
}

#undef mid
#undef rson
#undef lson

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d%d", &n, &s, &m), build(1, n, 1);
    for (int i = 1; i <= n; i++)
        dp[sidx[i]] = 1;
    for (int i = 1, p, d; i <= s; i++)
        scanf("%d%d", &p, &d), dp[sidx[p]] = d, isFixed[sidx[p]] = true;
    while (m--)
    {
        int l, r, k, cpt, last = l - 1;
        scanf("%d%d%d", &l, &r, &k), cpt = ++ptot, last = l - 1;
        for (int i = 1, pt; i <= k; i++)
            scanf("%d", &pt), addpath(sidx[pt], cpt, 1), update(last + 1, pt - 1, 1, n, 1, cpt), last = pt;
        update(last + 1, r, 1, n, 1, cpt);
    }
    queue<int> q;
    for (int i = 1; i <= ptot; i++)
        if (deg[i] == 0)
            q.push(i);
    while (!q.empty())
    {
        int u = q.front();
        q.pop(), topoidx[++topotot] = u;
        for (int i = head[u]; i != -1; i = edges[i].nxt)
            if (--deg[edges[i].to] == 0)
                q.push(edges[i].to);
    }
    for (int i = 1; i <= ptot; i++)
        if (deg[i] != 0)
            puts("NIE"), exit(0);
    for (int id = ptot; id >= 1; id--)
    {
        int u = topoidx[id], max_val = 1;
        for (int i = head[u]; i != -1; i = edges[i].nxt)
            max_val = max(max_val, dp[edges[i].to] + edges[i].weight);
        if (isFixed[u] && max_val > dp[u])
            puts("NIE"), exit(0);
        else if (!isFixed[u])
            dp[u] = max_val;
    }
    for (int i = 1; i <= n; i++)
        if (dp[sidx[i]] > 1e9 || dp[sidx[i]] < 1)
            puts("NIE"), exit(0);
    puts("TAK");
    for (int i = 1; i <= n; i++)
        printf("%d%c", dp[sidx[i]], " \n"[i == n]);
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *