3.24训练赛

A.CF1657D For Gamers. By Gamers.

推一下式子发现要求是\(C/c*dh > DH\),所以先处理每个单位价格对应最大\(dh\)
再更新每多买一个单位时的贡献,复杂度\(nlogn\)

#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 sz(x) ll(x.size())
#define all(x) x.begin(), x.end()
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ld = long double;
using LL = __int128;
using pll = pair<ll, ll>;
constexpr ll N = 1e6 + 1;
ll t, n, m, k;
ll c, d, h, a[N], b[N];

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> m;
    fu(i, 1, n) {
        cin >> c >> d >> h;
        mx(a[c], d * h);
    }
    fu(i, 1, m) fu(j, 1, m / i) mx(b[j * i], j * a[i]);
    fu(i, 2, m) mx(b[i], b[i - 1]);
    cin >> k;
    fu(i, 1, k) {
        cin >> d >> h;
        int p = upper_bound(b + 1, b + m + 1, d * h) - b;
        cout << (p > m ? -1 : p) << ' ';
    }
}

B.CF1657E Star MST

由最小生成树的定义有\(w(u, v) \geq max(\ w(1, u),\ w(1,v)\ )\),令\(f[i][j]\)
代表考虑\(i\)个点的完全图,与\(1\)相连的边最大值为\(j\)的方案数,转移时枚举有多少条
\(1\)相连的边被设置为\(j\)

#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define all(x) x.begin(), x.end()
#define sz(x) int(x.size())
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using LL = __int128;
using ll = long long;
using ld = long double;
using pll = pair<ll, ll>;
constexpr int N = 3e2 + 10, M = 998244353;
ll t, n, m, k, a, b;
ll f[N][N], c[N][N]{1};

inline ll qpow(ll a, ll b) {
    ll r = 1;
    for (; b; b >>= 1, a = a * a % M)
        if (b & 1)
            r = r * a % M;
    return r;
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> k;
    fu(i, 1, n) {
        c[i][0] = 1;
        fu(j, 1, n - 1) c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % M;
    }
    f[1][0] = 1;
    fu(i, 1, n) fu(j, 1, k) {
        fu(l, 0, i - 1) {
            t = (l - 1) * l / 2 + l * (i - 1 - l);
            f[i][j] += c[i - 1][l] * f[i - l][j - 1] % M * qpow(k - j + 1, t) % M;
        }
        f[i][j] %= M;
    }
    cout << f[n][k];
}

C.CF1657F Words on Tree

分析一下限制,每个点最多有两个选择,再加两个点对应一个单词正反读,2-sat解决。

#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define all(x) x.begin(), x.end()
#define sz(x) int(x.size())
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
constexpr int N = 4e5 + 1, M = 1.6e6 + 1;
int n, m, u, v, d[N], p[N], fa[N];
int c, sc, no, st[M], sn[M], dfn[M], low[M];
char w[N * 2];
string s;
vector<int> g[N], G[M];

void dfs(int u = 1) {
    for (int v : g[u])
        if (v ^ fa[u])
            d[v] = d[u] + 1, fa[v] = u, dfs(v);
}

void ins(int u, int v, int no, string s) {
    int len = sz(s), l = 0, r = len - 1;
    while (l <= r)
        if (d[u] > d[v])
            p[l++] = u, u = fa[u];
        else
            p[r--] = v, v = fa[v];
    fu(i, 0, len - 1) {
        int x = p[i];
        if (!w[x])
            w[x] = s[i], w[x + n] = s[len - 1 - i];
        int l[]{x, x + n}, r[]{no, no + m}, c[]{s[i], s[len - 1 - i]};
        fu(i, 0, 1) fu(j, 0, 1) if (w[l[i]] ^ c[j]) {
            G[l[i]].emplace_back(r[!j]);
            G[r[j]].emplace_back(l[!i]);
        }
    }
}

void tarjan(int x) {
    dfn[x] = low[x] = ++no, st[c++] = x;
    for (int y : G[x])
        if (!dfn[y])
            tarjan(y), mn(low[x], low[y]);
        else if (!sn[y])
            mn(low[x], dfn[y]);
    if (low[x] == dfn[x]) {
        ++sc;
        while (st[c] ^ x)
            sn[st[--c]] = sc;
    }
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> m;
    fu(i, 2, n) {
        cin >> u >> v;
        g[u].emplace_back(v), g[v].emplace_back(u);
    }
    dfs();
    fu(i, 1, m) cin >> u >> v >> s, ins(u, v, 2 * n + i, s);
    fu(i, 1, n + m << 1) dfn[i] ? void() : tarjan(i);
    fu(i, 1, n) if (sn[i] == sn[i + n]) return puts("NO");
    cout << "YES\n";
    fu(i, 1, n) cout << (w[i] ? sn[i] < sn[i + n] ? w[i] : w[i + n] : 'a');
}

D.BZOJ4917 Hash Killer IV

反向模拟即可,核心是利用未改变的位进行还原,另外t += t << 3的操作也可以用逆元还原
(乘数与模数互质)。

#include <bits/extc++.h>
#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define all(x) x.begin(), x.end()
#define sz(x) int(x.size())
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ui = unsigned int;
constexpr int N = 4e5 + 1, M = 8e5 + 2;
ui t, n;

void cal(ui &x, int l) {
    auto y = x;
    fu(i, 1, 31 / l) x ^= y >> i * l;
}

void cal(int l, ui &x) {
    static bool y[32], f[32];
    bitset<32> z(x);
    fu(i, 0, 31) y[i] = z[i];
    fu(i, l, 31) {
        y[i] ^= y[i - l], z[i] = y[i];
        f[i] = y[i] + y[i - l] + (i > l ? f[i - 1] : 0) > 1;
        i < 31 ? y[i + 1] ^= f[i] : 0;
    }
    x = z.to_ullong();
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    cin >> t;
    while (t--) {
        cin >> n;
        n -= n << 16, cal(n, 11);
        cal(3, n), cal(n, 6), cal(10, n);
        cout << n << '\n';
    }
}

E.BZOJ3098 Hash Killer II

首先在此谢罪,没考虑到没人维护题目spj的情况,只好自己写了一个传题到洛谷
仅供参考
考虑随机,\(base \geq 26\)时hash值不超过mod时是准确的,最大值%mod与
最大值/mod较小时冲突率也会降低,可以取\(l = 8\)

import random
from string import ascii_lowercase

n = 10 ** 5
print(n, 8)
for i in range(n // 10):
    for c in random.sample(ascii_lowercase, 10):
        print(c, end='')

F.CF1654C Alice and the Cake

贪心+模拟

#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 sz(x) ll(x.size())
#define all(x) x.begin(), x.end()
#define f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ld = long double;
using LL = __int128;
using pll = pair<ll, ll>;
constexpr ll N = 1e6 + 1;
ll t, n, m, a, b, c, d, l, r, k;
ll x[N];

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> t;
    fu(_, 1, t) {
        cin >> n, a = 0;
        fu(i, 1, n) cin >> x[i], a += x[i];
        sort(x + 1, x + n + 1, greater<ll>());
        multiset<ll, greater<ll>> s;
        s.emplace(a);
        for (int i = 1; i <= n;) {
            while (*s.begin() ^ x[i]) {
                if (*s.begin() < x[i] || *s.begin() < 2) {
                    cout << "NO\n";
                    goto end;
                }
                a = *s.begin(), s.erase(s.begin());
                s.emplace(a / 2), s.emplace(a / 2 + (a & 1));
            }
            s.erase(s.begin()), ++i;
        }
        cout << "YES\n";
    end:;
    }
}

G.CF1654D Potion Brewing Class

我们可以设一号药用量为\(1\),剩下的为\(\frac{a_i}{b_i}\),那么依题意一号药
原用量为\(\mathrm lcm \{b_i\}\),所以我们可以dfs维护分母质因数集合,
求出一号药用量后再dfs一遍求答案。

#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define sz(x) int(x.size())
#define all(x) x.begin(), x.end()
#define f first
#define s second
using namespace std;
using ll = long long;
using pii = pair<int, int>;
constexpr int N = 2e5 + 1, M = 998244353;
int t, n, a, b, c, d, e, val[N], ans;

int qpow(int a, int b) {
    int r = 1;
    for (; b; b >>= 1, a = (ll)a * a % M)
        b & 1 ? r = (ll)r * a % M : 0;
    return r;
}

int exgcd(int a, int b, int &x, int &y) {
    if (!b)
        return x = 1, y = 0, a;
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

int inv(int a) {
    int x, y;
    exgcd(a, M, x, y);
    return x + (x < 0 ? M : 0);
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> t;
    fu(_, 1, t) {
        cin >> n, ans = 0;
        vector<pair<int, pii>> g[n + 1];
        int cnt[n + 1]{}, mx[n + 1]{};
        fu(i, 2, n) {
            cin >> a >> b >> c >> d;
            e = gcd(c, d), c /= e, d /= e;
            g[a].emplace_back(b, pii{d, c});
            g[b].emplace_back(a, pii{c, d});
        }

        auto upd = [&](int x, int f) {
            fu(i, 2, sqrt(x)) while (!(x % i))
                x /= i,
                mx(mx[i], cnt[i] += f);
            mx(mx[x], cnt[x] += f);
        };
        function<void(int, int)> dfs = [&](int u, int f) {
            for (auto [v, F] : g[u])
                if (v ^ f) {
                    upd(F.f, -1), upd(F.s, 1), dfs(v, u);
                    upd(F.s, -1), upd(F.f, 1);
                }
        };
        dfs(1, 0), a = 1;
        fu(i, 2, n) a = (ll)a * qpow(i, mx[i]) % M;
        val[1] = a;

        function<void(int, int)> dfs1 = [&](int u, int f) {
            for (auto &[v, F] : g[u])
                if (v ^ f) {
                    val[v] = (ll)val[u] * F.f % M * inv(F.s) % M;
                    dfs1(v, u);
                }
        };
        dfs1(1, 0);
        cout << accumulate(val + 1, val + n + 1, 0ll) % M << '\n';
    }
}

H.BZOJ2618 [Cqoi2006]凸多边形

半平面交模板,这里用的暴力算法。

#include <bits/stdc++.h>
#define fu(a, b, c) for (int a = b; a <= c; a++)
#define fd(a, b, c) for (int a = b; a >= c; a--)
#define mx(a, b) a = max(a, b)
#define mn(a, b) a = min(a, b)
#define sz(x) int(x.size())
#define all(x) x.begin(), x.end()
#define x first
#define y second
using namespace std;
using ll = long long;
using db = double;
using pdd = pair<db, db>;
using poly = vector<pdd>;
constexpr db eps = 1e-10;
constexpr int N = 50;
int n, m;

db operator^(pdd a, pdd b) {
    return a.x * b.y - a.y * b.x;
}

pdd operator-(pdd a, pdd b) {
    return {a.x - b.x, a.y - b.y};
}

pdd operator+(pdd a, pdd b) {
    return {a.x + b.x, a.y + b.y};
}

pdd operator*(pdd a, db x) {
    return {a.x * x, a.y * x};
}

pdd operator/(pdd a, db x) {
    return {a.x / x, a.y / x};
}

pdd inter(pdd s1, pdd e1, pdd s2, pdd e2) {
    db d = e1 - s1 ^ e2 - s2;
    db p = e1 - s2 ^ e2 - s2, q = e2 - s2 ^ s1 - s2;
    return (s1 * p + e1 * q) / d;
}

poly cut(poly &p, pdd s, pdd e) {
    poly r;
    const int n = sz(p);
    fu(i, 0, n - 1) {
        int j = (i + 1) % n;
        bool f0 = (s - p[i] ^ e - p[i]) > eps;
        bool f1 = (s - p[j] ^ e - p[j]) > eps;
        if (f0)
            r.emplace_back(p[i]);
        if (f0 ^ f1)
            r.emplace_back(inter(p[i], p[j], s, e));
    }
    return r;
}

void cut(poly &p, const poly &q) {
    int n = sz(q);
    fu(i, 0, n - 1) p = cut(p, q[i], q[(i + 1) % n]);
}

db area(const poly &p) {
    db r = 0;
    int n = sz(p);
    fu(i, 0, n - 1) r += p[i] ^ p[(i + 1) % n];
    return r / 2;
}

int main() {
    cin.tie(0)->sync_with_stdio(0);
    cin >> n >> m;
    poly p(m), q;
    fu(i, 0, m - 1) cin >> p[i].x >> p[i].y;
    fu(i, 2, n) {
        cin >> m, q.resize(m);
        fu(j, 0, m - 1) cin >> q[j].x >> q[j].y;
        cut(p, q);
    }
    cout << fixed << setprecision(3) << area(p);
}
posted @ 2022-03-26 23:38  lemu  阅读(80)  评论(0编辑  收藏  举报
4