9.16训练赛

A. P7482 不条理狂诗曲

分治,详见代码。

#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define f first
#define s second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
const ll N = 1e5 + 1, M = 1e9 + 7;
ll t, n, m;
ll a, b, c, d;
ll x[N], ans;
ll ml[N], nl[N], mr[N], nr[N], sm[N], sn[N];
pll p[N];

inline bool lt(const pll &a, const pll &b) {
    return a.f - a.s < b.f - b.s;
}

inline void cal(ll l, ll r) {
    if (l == r)
        return ans += x[l], void();
    ll m = l + r >> 1;
    cal(l, m), cal(m + 1, r); //在中点两侧的子区间递归计算

    ml[m] = x[m], ml[m + 1] = 0;
    fd(i, m - 1, l) ml[i] = max(ml[i + 1], ml[i + 2] + x[i]); //选取中点,往左dp
    mr[m + 1] = 0, mr[m + 2] = x[m + 2];
    fu(i, m + 3, r) mr[i] = max(mr[i - 1], mr[i - 2] + x[i]); //选取中点,往右dp

    nl[m] = 0, nl[m - 1] = x[m - 1];
    fd(i, m - 2, l) nl[i] = max(nl[i + 1], nl[i + 2] + x[i]); //不选中点,往左dp
    nr[m] = 0, nr[m + 1] = x[m + 1];
    fu(i, m + 2, r) nr[i] = max(nr[i - 1], nr[i - 2] + x[i]); //不选中点,往右dp
    //计算跨过中点的子区间
    //f(l,r) = max(ml[l] + mr[r], nl[l] + nr[r])
    //如果 ml[l] + mr[r] < nl[l] + nr[r]
    //则 ml[l] - nl[l] < nr[r] - mr[r]
    //那么对左端点按ml[l] - nl[l]排序即可nlogn得到答案
    c = 0;
    // debug用
    // fu(i, l, m) fu(j, m + 1, r) ans += max(ml[i] + mr[j], nl[i] + nr[j]);
    fu(i, l, m) p[++c] = {ml[i], nl[i]};
    sort(p + 1, p + c + 1, lt);
    fu(i, 1, c) sm[i] = sm[i - 1] + p[i].f, sn[i] = sn[i - 1] + p[i].s;
    fu(i, m + 1, r) {
        ll pos = upper_bound(p + 1, p + c + 1, pll{nr[i], mr[i]}, lt) - p - 1;
        ans += sm[c] - sm[pos] + mr[i] * (c - pos);
        ans += sn[pos] + nr[i] * pos;
        ans %= M;
    }
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    fu(i, 1, n) cin >> x[i];
    cal(1, n);
    cout << ans;
}

B. P7863 「EVOI-RD1」飞鸟和蝉

每个点向周围地势比它低的点连边,问题就转为二分图匹配,推一下柿子可以发现体力消耗就是每条边两点权值差的和,也就是二分图最小权匹配,跑个mcmf即可。这题spfa跑的比较快,堆优化dijkstra要用pbds里的堆(stl的T了)。

#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef pair<ll, ll> pll;
const ll N = 5e3 + 2, M = 2e4 + 1, inf = 1e18;
ll n, m, a, b, tot, s, t;
ll cnt, he[N], d[N], h[N], x[51][51];
ll ne[M], to[M], c[M], w[M];
ll pe[N], pv[N], F, C;

inline void add(ll u, ll v, ll C, ll W) {
    ne[cnt] = he[u], to[cnt] = v, c[cnt] = C, w[cnt] = W, he[u] = cnt++;
    ne[cnt] = he[v], to[cnt] = u, c[cnt] = 0, w[cnt] = -W, he[v] = cnt++;
}

inline ll get_no(ll i, ll j) {
    return (i - 1) * m + j;
}

inline bool dij(ll s, ll t) {
    __gnu_pbds::priority_queue<pll, greater<pll>, pairing_heap_tag> q;
    memset(d, 14, sizeof d), d[s] = 0;
    q.push({0, s});
    while (q.size()) {
        pll T = q.top();
        q.pop();
        ll u = T.second;
        if (d[u] < T.first)
            continue;
        for (ll i = he[u]; ~i; i = ne[i]) {
            ll v = to[i], tw = d[u] + w[i] + h[u] - h[v];
            if (c[i] && tw < d[v]) {
                d[v] = tw, pv[v] = u, pe[v] = i;
                q.push({d[v], v});
            }
        }
    }
    return d[t] < inf;
}

inline void mcmf(ll s, ll t) {
    while (dij(s, t)) {
        fu(i, 1, t) h[i] += d[i];
        ll f = inf;
        for (ll u = t; u ^ s; u = pv[u])
            mn(f, c[pe[u]]);
        F += f, C += h[t] * f;
        for (ll u = t; u ^ s; u = pv[u]) {
            c[pe[u]] -= f;
            c[pe[u] ^ 1] += f;
        }
    }
}

int main() {
    scanf("%lld%lld%lld%lld", &n, &m, &a, &b);
    tot = n * m;
    fu(i, 1, n) fu(j, 1, m) scanf("%lld", x[i][j]);
    memset(he, -1, sizeof he);
    ll dx[]{0, 0, 1, -1}, dy[]{1, -1, 0, 0}, o = 0;

    s = 0, t = 2 * tot + 1;
    fu(i, 1, n) fu(j, 1, m) {
        ++o;
        add(0, o, 1, 0);
        add(o + tot, t, 1, 0);
        fu(k, 0, 3) {
            ll nx = i + dx[k], ny = j + dy[k], no = get_no(nx, ny);
            if (nx >= 1 && nx <= n && ny >= 1 && ny <= m)
                if (x[i][j] > x[nx][ny])
                    add(o, no + tot, 1, x[i][j] - x[nx][ny]);
        }
    }

    mcmf(s, t);
    printf("%lld %lld", tot - F, C);
}

C. P7835 「Wdoi-3」夜雀 dreaming

签到题,解同余方程或者利用周期性只需判断lcm和二倍lcm。

#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define f first
#define s second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> pll;
const ll N = 1e5 + 1, M = 1e9 + 7;
ll n, m;
ll a, b, c, d, l;
ll x[N], y[N], t[N], ans = 2e18;
ll exgcd(ll a, ll b, ll &x, ll &y) {
    if (!b)
        return x = 1, y = 0, a;
    ll t = exgcd(b, a % b, y, x);
    return y -= a / b * x, t;
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> m;
    fu(i, 1, m) cin >> t[i] >> x[i] >> y[i];
    fu(i, 1, m - 1) fu(j, i + 1, m) {
        d = __gcd(t[i], t[j]);
        l = t[i] * t[j] / d;
        a = t[j] / d, b = t[i] / d;
        a = a * y[i] - b * y[j];
        c = x[j] - x[i] + y[i] - y[j];
        ll x, y;
        d = abs(exgcd(a, n, x, y));
        if (c % d) {
            mn(ans, l);
        } else if (n / d > 1) {
            a = n / d;
            c = (x * c / d % a + a) % a;
            mn(ans, (c ^ 1 ? 1 : 2) * l);
        }
    }
    if (ans == 2e18)
        cout << "Mystia will cook forever...";
    else
        cout << ans - 1;
}

D. T183638 晚宴(2021 CoE III E)

显然是个二分图最小权匹配,用堆优化dijkstra或者\(O(n ^ 3)\)的km算法,spfa应该卡不过。

#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define pii pair<ll, ll>
using namespace std;
typedef long long ll;
const ll N = 1.5e3, M = 5e5, inf = 1e18;
ll n, m, s, t;
ll cnt, he[N], d[N], h[N];
ll ne[M], to[M], c[M], w[M];
ll pe[N], pv[N], nx[N], vis[N], F, C;

inline void add(ll u, ll v, ll C, ll W) {
    ne[cnt] = he[u], to[cnt] = v, c[cnt] = C, w[cnt] = W, he[u] = cnt++;
    ne[cnt] = he[v], to[cnt] = u, c[cnt] = 0, w[cnt] = -W, he[v] = cnt++;
}

inline bool dij(ll s, ll t, ll m) {
    priority_queue<pii, vector<pii>, greater<pii>> q;
    memset(d, 14, sizeof d), d[s] = 0;
    q.push({0, s});
    while (q.size()) {
        pii T = q.top();
        q.pop();
        ll u = T.second;
        if (d[u] < T.first)
            continue;
        for (ll i = he[u]; ~i; i = ne[i]) {
            ll v = to[i], tw = d[u] + w[i] + h[u] - h[v];
            if (c[i] && tw < d[v]) {
                d[v] = tw, pv[v] = u, pe[v] = i;
                q.push({d[v], v});
            }
        }
    }
    return d[t] < inf;
}

inline void mcmf(ll s, ll t, ll m) {
    while (dij(s, t, m)) {
        fu(i, 1, m) h[i] += d[i];
        ll f = inf;
        for (ll u = t; u ^ s; u = pv[u])
            mn(f, c[pe[u]]);
        F += f, C += h[t] * f;
        for (ll u = t; u ^ s; u = pv[u]) {
            nx[pv[u]] = u - n;
            c[pe[u]] -= f;
            c[pe[u] ^ 1] += f;
        }
    }
}

int main() {
    ll u, v, c, w;
    memset(he, -1, sizeof he);
    scanf("%lld%lld", &n, &m);
    s = 0, t = 2 * n + 1;
    fu(i, 1, n) {
        add(0, i, 1, 0);
        add(i + n, t, 1, 0);
    }
    fu(i, 1, m) {
        scanf("%lld%lld%lld", &u, &v, &w);
        add(u, v + n, 1, w);
    }
    mcmf(s, t, 2 * n + 1);
    if (F ^ n)
        puts("Impossible!");
    else {
        printf("%lld\n", C);
        fu(i, 1, n) {
            if (!vis[i]) {
                for (ll j = i; !vis[j]; vis[j] = 1, j = nx[j])
                    printf("%lld ", j);
                puts("");
            }
        }
    }
    return 0;
}

E. P3769 [CH弱省胡策R2]TATT

四维偏序,我写的是cdq套cdq,不会kd-tree。

#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define g(a, b) get<b>(a)
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
typedef tuple<ll, ll, ll, ll, ll, ll, ll> tp; //a, b, c, d, ans, cnt, f
const ll N = 1e5 + 10, M = 998244353;
ll t, n, m, k, ans;
ll a, b, c, d, e, f;
ll x[N], y[N], T[N], tot;
tp p[N], p1[N];

auto cmp2 = [](tp &a, tp &b) { return g(a, 1) ^ g(b, 1) ? g(a, 1) < g(b, 1) : a < b; };
auto cmp3 = [](tp &a, tp &b) { return g(a, 2) < g(b, 2); };

inline void upd(ll p, ll x) {
    for (; p <= tot; p += p & -p)
        mx(T[p], x);
}

inline void clr(ll p) {
    for (; p <= tot; p += p & -p)
        T[p] = 0;
}

inline ll ask(ll p) {
    ll r = 0;
    for (; p; p -= p & -p)
        mx(r, T[p]);
    return r;
}

void cal1(ll l, ll r) {
    if (l == r)
        return;
    ll m = l + r >> 1, j = l;
    cal1(l, m);
    sort(p + l, p + m + 1, cmp3);
    sort(p + m + 1, p + r + 1, cmp3);
    fu(i, m + 1, r) {
        auto &[a, b, c, d, ans, cnt, f] = p[i];
        for (; g(p[j], 2) <= c && j <= m; ++j)
            if (!g(p[j], 6))
                upd(g(p[j], 3), g(p[j], 4));
        if (f)
            mx(ans, ask(d) + cnt);
    }
    fd(i, j - 1, l) if (!g(p[i], 6)) clr(g(p[i], 3));
    sort(p + l, p + r + 1, cmp2);
    cal1(m + 1, r);
}

void cal(ll l, ll r) {
    if (l == r)
        return;
    ll m = l + r >> 1;
    cal(l, m);
    fu(i, l, r) g(p[i], 6) = i > m;
    sort(p + l, p + r + 1, cmp2);
    cal1(l, r);
    sort(p + l, p + r + 1);
    cal(m + 1, r);
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n;
    fu(i, 1, n) {
        cin >> a >> b >> c >> x[i];
        p[i] = {a, b, c, x[i], 0, 0, 0};
    }
    //对第四维离散化
    sort(x + 1, x + n + 1);
    tot = unique(x + 1, x + n + 1) - x - 1;
    gp_hash_table<ll, ll> ht;
    fu(i, 1, tot) ht[x[i]] = i;
    fu(i, 1, n) g(p[i], 3) = ht[g(p[i], 3)];
    //按第一维排序,去重
    sort(p + 1, p + n + 1);
    t = 1;
    fu(i, 2, n + 1) if (p[i] != p[t]) {
        p[++m] = p[t];
        g(p[m], 4) = g(p[m], 5) = i - t;
        t = i;
    }

    cal(1, m);
    fu(i, 1, m) mx(ans, g(p[i], 4));
    cout << ans;
}

F. P3369 【模板】普通平衡树

方法很多,这里直接用pbds里的rb_tree

#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (ll a = b; a <= c; a++)
#define fd(a, b, c) for (ll a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
using namespace __gnu_pbds;
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<ll, ll> pll;
const ll N = 1e5 + 10, M = 998244353;
ll t, n, m, k, ans;
ll a, b, c, d, e, f;
ll x[N], y[N], z[N];
pll p[N];

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    tree<ll, null_type, less<ll>, rb_tree_tag, tree_order_statistics_node_update> T;
    cin >> t;
    fu(i, 1, t) {
        cin >> a >> b;
        switch (a) {
        case 1:
            T.insert((b << 17) + i);
            break;
        case 2:
            T.erase(T.lower_bound(b << 17));
            break;
        case 3:
            cout << T.order_of_key(b << 17) + 1 << '\n';
            break;
        case 4:
            cout << (*T.find_by_order(b - 1) >> 17) << '\n';
            break;
        case 5:
            cout << (*--T.lower_bound(b << 17) >> 17) << '\n';
            break;
        case 6:
            cout << (*T.lower_bound(b + 1 << 17) >> 17) << '\n';
            break;
        }
    }
}
posted @ 2021-09-30 01:14  lemu  阅读(36)  评论(0编辑  收藏  举报
4