2.3训练赛

A.CF489E Hiking

01分数规划,二分答案,\(\sum a_i / \sum b_i <= k \ \Rightarrow \sum a_i - k b_i <= 0\),对于确定的\(k\)用dp判定。

#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 f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ld = long double;
using pll = pair<ll, ll>;
const ld eps = 1e-8;
const ll N = 1e3 + 1;
ll n, m, x[N], y[N], p[N];
ld l, r, d[N];

inline bool ck(ld a) {
    fu(i, 1, n) {
        d[i] = N;
        fu(j, 0, i - 1) {
            ld t = d[j] + sqrtl(abs(x[i] - x[j] - m)) - a * y[i];
            if (t < d[i])
                d[i] = t, p[i] = j;
        }
    }
    return d[n] < eps;
}

inline void out(ll i) {
    if (!i)
        return;
    out(p[i]);
    cout << i << ' ';
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> m;
    fu(i, 1, n) cin >> x[i] >> y[i];
    r = N;
    while (r - l > eps) {
        ld m = (l + r) / 2;
        ck(m) ? r = m : l = m;
    }
    out(n);
}

B.CF1476C Longest Simple Cycle

遍历每条链,如果\(a_i \not= b_i\),那么可以尝试往前扩展,否则只能从重合的点出发。

#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 f first
#define s second
using namespace std;
using namespace __gnu_pbds;
using ll = long long;
using ld = long double;
using pll = pair<ll, ll>;
const ld eps = 1e-8;
const ll N = 1e5 + 1;
ll t, n, m, a, b, c, d, e, f;
ll x[N], y[N], z[N], p[N];

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> t;
    while (t--) {
        cin >> n, f = c = 0;
        fu(i, 1, n) cin >> x[i];
        fu(i, 1, n) cin >> y[i];
        fu(i, 1, n) cin >> z[i];
        fu(i, 2, n) {
            a = abs(z[i] - y[i]);
            if (c)
                c = a ? c + x[i - 1] - a + 1 : 2;
            mx(c, a + 2), mx(f, c + x[i] - 1);
        }
        cout << f << '\n';
    }
}

C.CF1480D1 Painting the Array I

贪心,注意当前数与两个序列末尾都不相同时如果下一个数与其中一个序列末尾相同要插在这后面。
这可以保证对于连续两个相同数不损失贡献,而连续三个及以上的数只有前两个有贡献。

import io
import os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

n = int(input())
a = list(map(int, input().split()))
a.append(0)
b, c, d = 0, 0, 0
for i in range(n):
    if a[i] ^ b:
        if a[i] ^ c:
            if a[i + 1] ^ b:
                c = a[i]
            else:
                b = a[i]
        else:
            b = a[i]
        d += 1
    else:
        if a[i] ^ c:
            d += 1
        c = a[i]
print(d)

D.CF1480D2. Painting the Array II

当前数与两个序列末尾都不相同时,优先保留下一个相同数更近的序列。这样保证构造连续相同序列
的代价尽可能小,可以联想最佳页面置换算法。

import io
import os
input = io.BytesIO(os.read(0, os.fstat(0).st_size)).readline

n = int(input())
a = list(map(int, input().split()))
p = [[] for i in range(n + 1)]
for i in range(n):
    p[a[i]].append(i)
for i in range(n + 1):
    p[i].append(n)
b, c, d = 0, 0, 0

for i in range(n):
    if a[i] ^ b and a[i] ^ c:
        while p[b][0] < i:
            p[b].pop(0)
        while p[c][0] < i:
            p[c].pop(0)
        if p[b][0] < p[c][0]:
            c = a[i]
        else:
            b = a[i]
        d += 1
print(d)

E.CF1480C Searching Local Minimum

这题之前周赛有过来着,忘了换,二分找波谷,顺着坡往下滑。

l, r = 1, int(input())
while l < r:
    m = l + r >> 1
    print('?', m, ' ?', m+1)
    if int(input()) > int(input()):
        l = m + 1
    else:
        r = m
print('!', l,)

F.CF1466F Euclid's nightmare

k = 1说明该位是自由的,k = 2时有两位可以同步改变。如果这两位中有可以自由改变的位,
那么都可以自由改变,用并查集维护。

#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)
using namespace std;
typedef long long ll;
const int N = 5e5 + 2, M = 1e9 + 7;
ll t, n, m, k, a, b, c, d, e, f;
ll x[N], y[N], fa[N], v[N];

inline ll find(ll x) { return fa[x] ? fa[x] = find(fa[x]) : x; }

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> t >> n;
    f = 1;
    fu(i, 1, t) {
        cin >> m >> a;
        b = n + 1;
        if (m == 2)
            cin >> b;
        ll fx = find(a), fy = find(b);
        if (fx ^ fy)
            fa[fx] = fy, y[i] = 1, ++c, f = (f << 1) % M;
    }
    cout << f << ' ' << c << '\n';
    fu(i, 1, t) if (y[i]) cout << i << ' ';
}

G.CF1633E Spanning Tree Queries

考虑对于任意两条边仅当\(x\)跨过两边权重和的平均值时两边的相对大小发生改变,所以
边的排列顺序有\(O(m^2)\)种,再考虑同一种排列下限定\(x\)的范围使得\(x\)相对
所有边的大小关系不变就可以轻松转移。

#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 f first
#define s second
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int N = 1e6 + 10;
int n, m, p, k, a, b, c, x, sz, pre[N];
ll w[N], ans;
pair<int, pii> e[N];
vector<int> v;

inline void qry() {
    int p = lower_bound(&v[0], &v[sz], x) - &v[0];
    ans ^= w[p] + ll(v[p] - x) * (n - 1 - 2 * pre[p]);
}

signed main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> n >> m;
    fu(i, 1, m) cin >> e[i].s.f >> e[i].s.s >> e[i].f;
    fu(i, 1, m) fu(j, i, m) {
        int w = e[i].f + e[j].f >> 1;
        v.emplace_back(w), v.emplace_back(w - 1), v.emplace_back(w + 1);
    }
    v.emplace_back(1e8), sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end()), sz = v.size();
    fu(i, 0, sz - 1) {
        int f[n + 1]{}, c = n - 1;
        function<int(int)> fa = [&](int x) { return f[x] ? f[x] = fa(f[x]) : x; };
        sort(e + 1, e + m + 1, [&](auto &x, auto &y) {
            return abs(x.f - v[i]) < abs(y.f - v[i]);
        });
        fu(j, 1, m) {
            int fu = fa(e[j].s.f), fv = fa(e[j].s.s);
            if (fu ^ fv) {
                f[fu] = fv, w[i] += abs(e[j].f - v[i]);
                pre[i] += (e[j].f < v[i]), --c;
            }
            if (!c)
                break;
        }
    }
    cin >> p >> k >> a >> b >> c;
    fu(i, 1, p) cin >> x, qry();
    fu(i, p + 1, k) x = (1ll * x * a + b) % c, qry();
    cout << ans;
}

H.CF1633C Kill the Monster

暴力模拟,似乎有\(O(1)\)做法,待补。

#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;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef long double ld;
const ll N = 1e5 + 10, M = 998244353;
ll t, n, m, k, ans;
ll a, b, c, d, e, f, g;
ll x[N], y[N];
pll p[N];
vector<ll> vx[N], vy[N];
string s;

bool ck(ll a, ll b) {
    ll damage = (a + d - 1) / d * b;
    return damage >= c;
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0);
    cin >> t;
    while (t--) {
        cin >> a >> b >> c >> d >> e >> f >> g;
        fu(i, 0, e) if (ck(a + g * i, b + f * (e - i))) {
            cout << "YES";
            goto end;
        }
        cout << "NO";
    end:
        cout << '\n';
    }
}
posted @ 2022-02-04 03:13  lemu  阅读(55)  评论(0编辑  收藏  举报
4