Featured image of post 2100

2100

GCD Queries

出处:CF1762D

题目大意:交互题,给定一个秘密的 $[0,n-1]$ 排列 $p$ ,请在至多 $2n$ 次询问下,找出 $p_x$ 和 $p_y$ 其中,至少有一个位置为 $0$ ,每次询问给出 $i,j$ ,返回 $gcd(i,j)$ 。

数据范围: $2 \leq n \leq 2 \cdot 10^4$ 。

思路:这道题其实跟CF1634D 非常相似,思路都是动态更新当前可能的解。

于是,这里考虑每次判断三个数,要排除掉一个必然不是0的数,于是如何排除?

考虑当前的数为 $a,b,c$ ,查询 $gcd(a,b)$ 和 $gcd(a,c)$ 。

若 $gcd(a,b)=gcd(a,c)$ ,那么 $a$ 必然不是 $0$ 。

若 $gcd(a,b)>gcd(a,c)$ ,那么 $c$ 必然不是 $0$ ,可以使用反证法证明。

若 $gcd(a,b)<gcd(a,c)$ ,那么 $b$ 必然不是 $0$ ,可以使用反证法证明。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
int ask(int l, int r) {
    cout << "? " << l << ' ' << r << '\n';
    cout.flush();
    int op;
    cin >> op;
    return op;
}
void report(ll sum, ll sum2) {
    cout << "! " << sum << ' ' << sum2 << '\n';
    cout.flush();
    int op;
    cin >> op;
    if (op == 1)
        return;
    else
        exit(0);
}
void solve() {
    int n;
    cin >> n;
    pii ans = make_pair(1, 2);
    auto upd = [&](int x) -> void {
        int op1 = ask(ans.first, x);
        int op2 = ask(ans.second, x);
        if (op1 == op2)
            ans = make_pair(ans.first, ans.second);
        else if (op1 > op2)
            ans = make_pair(ans.first, x);
        else
            ans = make_pair(ans.second, x);
    };
    rep(i, 3, n) { upd(i); }
    report(ans.first, ans.second);
    return;
}

Time to Raid Cowavans

出处:CF103D

题目大意:

数据范围:

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void solve() {
    int n, q;
    int x, y;
    cin >> n;
    vl a(n);
    rep(i, 0, n - 1) cin >> a[i];
    int B = sqrt(n);
    cin >> q;
    vector<pii> tem(q);
    map<int, vi> ma;
    vl ans(q);
    rep(i, 0, q - 1) {
        cin >> tem[i].first >> tem[i].second;
        tem[i].first--;
        if (tem[i].second >= B) {
            ll tem2 = 0;
            for (int j = tem[i].first; j <= n - 1; j += tem[i].second) tem2 += a[j];
            ans[i] = tem2;
        } else
            ma[tem[i].second].push_back(i);
    }
    for (auto& [x, y] : ma) {
        vl pre(n);
        frep(i, n - 1, 0) {
            pre[i] = a[i];
            if (i + x <= n - 1) pre[i] += pre[i + x];
        }
        for (auto& p : y) ans[p] = pre[tem[p].first];
    }
    rep(i, 0, q - 1) cout << ans[i] << endl;
    return;
}

Longest Array Deconstruction

出处:CF1575L

题目大意:

数据范围:

思路:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// 模板地址:https://github.com/elainafan/Algorithms
#include <bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define lowbit(x) (x & (-x))
#define rep(i, x, y) for (int i = x; i <= y; i++)
#define frep(i, x, y) for (int i = x; i >= y; i--)
#define all(x) (x).begin(), (x).end()
#define all2(x) (x).rbegin(), (x).rend()
#define sz(a) (int)a.size()
#define pii pair<int, int>
#define pll pair<ll, ll>
#define tri tuple<int, int, int>
#define vi vector<int>
#define vl vector<ll>
#define vvi vector<vector<int>>
#define vvl vector<vector<ll>>
#define pq priority_queue
#define umap unordered_map
#define mset multiset
using namespace std;
struct Info {
    ll x;
    Info(ll a = 0) : x(a) {}
};
Info operator+(const Info& a, const Info& b) {
    Info c;
    c.x = max(a.x, b.x);
    return c;
}
template <typename T>
class SegmentTree {
    int n;
    vector<T> tree;
    T merge_val(T a, T b) const { return a + b; }  // 合并子树

    void maintain(int node) {  // 维护整棵树
        tree[node] = merge_val(tree[node * 2], tree[node * 2 + 1]);
    }

    void build(const vector<T>& a, int node, int l, int r) {
        if (l == r) {
            tree[node] = a[l];
            return;
        }
        int m = (l + r) / 2;
        build(a, node * 2, l, m);
        build(a, node * 2 + 1, m + 1, r);
        maintain(node);
    }  // 建树

    void update(int node, int l, int r, int i, T val) {
        if (l == r) {
            tree[node] = val;
            return;
        }
        int m = (l + r) / 2;
        if (i <= m)
            update(node * 2, l, m, i, val);
        else
            update(node * 2 + 1, m + 1, r, i, val);
        maintain(node);
    }  // 更新i处的值为val

    T query(int node, int l, int r, int ql, int qr) const {
        if (ql <= l && r <= qr) return tree[node];
        int m = (l + r) / 2;
        if (qr <= m) return query(node * 2, l, m, ql, qr);
        if (ql > m) return query(node * 2 + 1, m + 1, r, ql, qr);
        T l_res = query(node * 2, l, m, ql, qr);
        T r_res = query(node * 2 + 1, m + 1, r, ql, qr);
        return merge_val(l_res, r_res);
    }  // 查询[ql,qr]的值

    int find_first(int node, int l, int r, int ql, int qr, T val) const {
        if (r < ql || l > qr) return -1;
        if (tree[node] < val) return -1;
        if (l == r) return l;
        int m = (l + r) >> 1;
        int res = find_first(node << 1, l, m, ql, qr, val);
        if (res != -1) return res;
        return find_first(node << 1 | 1, m + 1, r, ql, qr, val);
    }  // 若遇到固定左端点的情况,需要使用全局变量(或者传入引用)记录前缀分段最大值,加一个被待求区间完全覆盖的剪枝

    int find_last(int node, int l, int r, int ql, int qr, T val) const {
        if (r < ql || l > qr) return -1;
        if (tree[node] < val) return -1;
        if (l == r) return l;
        int m = (l + r) >> 1;
        int res = find_last(node << 1 | 1, m + 1, r, ql, qr, val);
        if (res != -1) return res;
        return find_last(node << 1, l, m, ql, qr, val);
    }

public:
    SegmentTree(int n, T init_val) : SegmentTree(vector<T>(n, init_val)) {}

    SegmentTree(const vector<T>& a) : n(a.size()), tree(2 << bit_width(a.size() - 1)) { build(a, 1, 0, n - 1); }  // 传入一个数组维护

    void update(int i, T val) { update(1, 0, n - 1, i, val); }  // 更新i的值为val

    T query(int ql, int qr) const { return query(1, 0, n - 1, ql, qr); }  // 查询[ql,qr]的值

    T get(int i) const { return query(1, 0, n - 1, i, i); }  // 取出i处的值

    int find_first(int ql, int qr, T val) const { return find_first(1, 0, n - 1, ql, qr, val); }  // 查询[ql,qr]中第一个满足条件的下标

    int find_last(int ql, int qr, T val) const { return find_last(1, 0, n - 1, ql, qr, val); }  // 查询[ql,qr]中最后一个满足条件的下标
};
void solve() {
    int n;
    cin >> n;
    vi a(n);
    rep(i, 0, n - 1) {
        cin >> a[i];
        a[i]--;
    }
    map<int, vi> ma;
    vi tem;
    rep(i, 0, n - 1) {
        if (0 <= a[i] && a[i] <= i) {
            ma[a[i]].push_back(i - a[i]);
            tem.push_back(i - a[i]);
        }
    }
    if (ma.empty()) {
        cout << 0 << endl;
        return;
    }
    ranges::sort(tem);
    tem.erase(unique(all(tem)), tem.end());
    int m = sz(tem);
    SegmentTree<Info> tree(m, Info(0));
    int ans = 0;
    for (auto& [x, y] : ma) {
        vector<pii> tem2;
        for (int& p : y) {
            int tem3 = ranges::lower_bound(tem, p) - tem.begin();
            int tem4 = tree.query(0, tem3).x + 1;
            tem2.emplace_back(tem3, tem4);
            ans = max(ans, tem4);
        }
        for (auto& [x, y] : tem2) {
            tree.update(x, Info(max(tree.get(x).x, 1LL * y)));
        }
    }
    cout << ans << endl;
    return;
}

Destroying Roads

出处:CF543B

题目大意:

数据范围:

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
void solve() {
    int n, m, x, y, s1, t1, s2, t2, l1, l2;
    cin >> n >> m;
    vvi ma(n);
    rep(i, 0, m - 1) {
        cin >> x >> y;
        x--, y--;
        ma[x].push_back(y);
        ma[y].push_back(x);
    }
    cin >> s1 >> t1 >> l1 >> s2 >> t2 >> l2;
    s1--, t1--, s2--, t2--;
    vvi dis(n, vi(n, 1e6));
    queue<int> q;
    auto bfs = [&](int x) -> void {
        while (!q.empty()) q.pop();
        dis[x][x] = 0;
        q.push(x);
        while (!q.empty()) {
            int node = q.front();
            q.pop();
            for (int& p : ma[node]) {
                if (dis[x][p] == 1e6) {
                    dis[x][p] = dis[x][node] + 1;
                    q.push(p);
                }
            }
        }
        return;
    };
    rep(i, 0, n - 1) bfs(i);
    if (dis[s1][t1] > l1 || dis[s2][t2] > l2) {
        cout << -1 << endl;
        return;
    }
    int ans = dis[s1][t1] + dis[s2][t2];
    rep(i, 0, n - 1) {
        rep(j, 0, n - 1) {
            if (dis[s1][i] + dis[i][j] + dis[j][t1] <= l1 && dis[s2][i] + dis[i][j] + dis[j][t2] <= l2)
                ans = min(ans, dis[s1][i] + dis[i][j] + dis[j][t1] + dis[s2][i] + dis[j][t2]);
            if (dis[s1][i] + dis[i][j] + dis[j][t1] <= l1 && dis[s2][j] + dis[j][i] + dis[i][t2] <= l2)
                ans = min(ans, dis[s1][i] + dis[i][j] + dis[j][t1] + dis[s2][j] + dis[i][t2]);
        }
    }
    cout << m - ans << endl;
    return;
}

Olya and Energy Drinks

出处:CF877D

题目大意:

数据范围:

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int dx[4] = {0, 1, -1, 0};
int dy[4] = {1, 0, 0, -1};
void solve() {
    int n, m, k, sx, sy, fx, fy;
    cin >> n >> m >> k;
    vector<string> ma(n);
    rep(i, 0, n - 1) cin >> ma[i];
    cin >> sx >> sy >> fx >> fy;
    sx--, sy--, fx--, fy--;
    if (ma[sx][sy] == '#') {
        cout << -1 << endl;
        return;
    }
    queue<pii> q;
    q.emplace(sx, sy);
    vvi dis(n, vi(m, INT_MAX));
    dis[sx][sy] = 0;
    while (!q.empty()) {
        auto [x, y] = q.front();
        q.pop();
        rep(i, 0, 3) {
            rep(j, 1, k) {
                int ax = x + j * dx[i], ay = y + j * dy[i];
                if (ax < 0 || ax >= n || ay < 0 || ay >= m || ma[ax][ay] == '#') break;
                if (dis[ax][ay] < dis[x][y] + 1) break;
                if (dis[ax][ay] == dis[x][y] + 1) continue;
                dis[ax][ay] = dis[x][y] + 1;
                q.emplace(ax, ay);
            }
        }
    }
    cout << (dis[fx][fy] == INT_MAX ? -1 : dis[fx][fy]) << endl;
    return;
}

Connected Components?

出处:CF920E

题目大意:

数据范围:

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
void solve() {
    int n, m, x, y;
    cin >> n >> m;
    set<pii> edges;
    set<int> unvis;
    rep(i, 0, m - 1) {
        cin >> x >> y;
        edges.emplace(min(x - 1, y - 1), max(x - 1, y - 1));
    }
    rep(i, 0, n - 1) unvis.insert(i);
    queue<int> q;
    auto bfs = [&](int x) -> void {
        while (!q.empty()) q.pop();
        vi tem;
        q.push(x);
        unvis.erase(x);
        while (!q.empty()) {
            int node = q.front();
            q.pop();
            vi tem;
            for (int p : unvis) {
                if (!edges.count(make_pair(min(node, p), max(node, p)))) {
                    q.push(p);
                    tem.push_back(p);
                }
            }
            for (int p : tem) unvis.erase(p);
        }
    };
    vi res;
    rep(i, 0, n - 1) {
        if (unvis.count(i)) {
            int tem = sz(unvis);
            bfs(i);
            int tem2 = sz(unvis);
            res.push_back(tem - tem2);
        }
    }
    ranges::sort(res);
    cout << sz(res) << endl;
    for (int& p : res) cout << p << ' ';
    cout << endl;
    return;
}

Segments

出处:CF926J

题目大意:

数据范围:

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void solve() {
    int n;
    ll x, y;
    cin >> n;
    map<ll, ll> ma;
    int ans = 0;
    rep(i, 0, n - 1) {
        cin >> x >> y;
        auto it = ma.lower_bound(x);
        if (it != ma.begin()) {
            auto itt = prev(it);
            if (itt->second >= x) {
                it = itt;
            }
        }
        ans++;
        while (it != ma.end() && it->first <= y) {
            x = min(x, it->first);
            y = max(y, it->second);
            ans--;
            it = ma.erase(it);
        }
        ma[x] = y;
        cout << ans << ' ';
    }
    cout << endl;
    return;
}

Destroy it!

出处:CF1176F

题目大意:

数据范围:

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
void solve() {
    int n;
    ll x, y;
    cin >> n;
    vi l(n);
    vector<vector<pll>> ma(n);
    rep(i, 0, n - 1) {
        cin >> l[i];
        rep(j, 0, l[i] - 1) {
            cin >> x >> y;
            ma[i].emplace_back(x, y);
        }
    }
    vvl dp(n + 1, vl(10, LLONG_MIN / 3));
    dp[0][0] = 0;
    rep(i, 1, n) {
        dp[i] = dp[i - 1];
        vvl tem(4);
        for (auto& p : ma[i - 1]) tem[p.first].push_back(p.second);
        rep(j, 1, 3) sort(all2(tem[j]));
        rep(j, 0, 9) {
            if (j == 0) {
                ll tem2 = 0;
                if (!tem[1].empty()) tem2 = max(tem2, tem[1][0]);
                if (!tem[2].empty()) tem2 = max(tem2, tem[2][0]);
                if (!tem[3].empty()) tem2 = max(tem2, tem[3][0]);
                dp[i][j] = max(dp[i][j], dp[i - 1][(j - 1 + 10) % 10] + 2LL * tem2);
                if (sz(tem[1]) >= 2) dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + 2 * tem[1][0] + tem[1][1]);
                if (sz(tem[1]) >= 1 && sz(tem[2]) >= 1)
                    dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + min(tem[1][0], tem[2][0]) + 2 * max(tem[1][0], tem[2][0]));
                if (sz(tem[1]) >= 3) {
                    dp[i][j] = max(dp[i][j], dp[i - 1][(j - 3 + 10) % 10] + 2 * tem[1][0] + tem[1][1] + tem[1][2]);
                }
            } else {
                ll tem2 = 0;
                if (!tem[1].empty()) tem2 = max(tem2, tem[1][0]);
                if (!tem[2].empty()) tem2 = max(tem2, tem[2][0]);
                if (!tem[3].empty()) tem2 = max(tem2, tem[3][0]);
                dp[i][j] = max(dp[i][j], dp[i - 1][(j - 1 + 10) % 10] + tem2);
                if (sz(tem[1]) >= 2) {
                    if (j == 1)
                        dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + min(tem[1][0], tem[1][1]) + 2 * max(tem[1][0], tem[1][1]));
                    else
                        dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + tem[1][0] + tem[1][1]);
                }
                if (sz(tem[1]) >= 1 && sz(tem[2]) >= 1) {
                    if (j == 1)
                        dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + min(tem[1][0], tem[2][0]) + 2 * max(tem[1][0], tem[2][0]));
                    else
                        dp[i][j] = max(dp[i][j], dp[i - 1][(j - 2 + 10) % 10] + min(tem[1][0], tem[2][0]) + max(tem[1][0], tem[2][0]));
                }
                if (sz(tem[1]) >= 3) {
                    if (j <= 2)
                        dp[i][j] = max(dp[i][j], dp[i - 1][(j - 3 + 10) % 10] + tem[1][0] + tem[1][1] + tem[1][2] +
                                                     max({tem[1][0], tem[1][1], tem[1][2]}));
                    else
                        dp[i][j] = max(dp[i][j], dp[i - 1][(j - 3 + 10) % 10] + tem[1][0] + tem[1][1] + tem[1][2]);
                }
            }
        }
    }
    cout << *max_element(all(dp[n])) << endl;
    return;
}