2022 全國賽心得

在打完了北市賽後,順利進入了全國賽,全國賽在 $12/16, 12/17$ 舉辦,離北市賽比完有大概一個月的時間。

在這一個月的時間我請了公假,然後跟同學到費曼教室練習程式,前幾週因為有 $\text{NPSC}$,所以練的是團體賽,我跟 $\text{NPSC}$ 的隊友找一些 $\text{ICPC}$ 制的比賽打。比完 $\text{NPSC}$ 之後,我寫了一些 $\text{codeforces}$ 的題目,從我打過 $\text{round}$ 前幾場的題目去選,主要是在把之前沒解的題目寫一遍,然後在前一兩週,我跟同學挑了幾場 $\text{ICPC}$ 去打,因為全國賽的性質就是時間長、題目多,只是 $\text{ICPC}$ 沒有部分分。在前一週有全國模擬賽,我拿了 $377.5$ 分,有點慘,不過很神奇的在第五名。

$12/16$ 我們從建中出發,搭火車到新竹,然後有接駁車載我們到清大,一開始是開幕典禮、測機,然後我們就去飯店吃晚餐了,晚餐好多海鮮,吃不了,所以我在晚餐後另外去便利商店買。

$12/17$ 早餐吃飯店的自助餐,吃完就到考場,這次考試有好多東西要設置,像是螢幕要調黑色風格、夜間光線,然後還要用 $\text{terminal}$ 把螢幕亮度調到 $0.8$ 倍,$\text{codeblocks}$ 要改字體、改編譯器的東西,還要打 $\text{default code}$。


接下來我一題一題講我的解法:

題本連結

$\text{pA. 基地駐守 (base)}$

$0/100$:我的想法是做完全點對最短路後去 $\text{random}$ 一些東西,但一直都拿不到分。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

//#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

mt19937 seed (time (NULL));
#define rnd(l,r) uniform_int_distribution<int>(l,r)(seed)

const int INF = 1e9;
const int SIZE = 505;

int n, m, s, x;
int w[SIZE], dis[SIZE][SIZE];
vector<tuple<int, int, int>> ans;
double point = 0;

int nk, nx;
int nw[SIZE], is[SIZE], vs[SIZE];

double power (double d, int up) {
    double re = 1;
    if (up < 0) up = -up, d = 1 / d;
    while (up) {
        if (up & 1) re = re * d;
        d = d * d;
        up >>= 1;
    }
    return re;
}

void work() {
    FOR (i, 1, n) {
        is[i] = 0;
        nw[i] = w[i];
        vs[i] = 0;
    }
    int X = rnd (x - 50, x), mx = 0;

    vector<tuple<int, int, int>> re;
    set<pair<int, int>> id;
    FOR (i, 1, n) id.emplace (nw[i], i);

    auto upd = [&] (int f, int i, int x) {
        if (x > 0) re.pb (f, i, x);
        else re.pb (i, f, -x);
        if (!vs[i]) {
            auto it = id.lower_bound ({nw[i], i});
            id.erase (it);
        }
        nw[i] += x;
        if (!vs[i]) id.emplace (nw[i], i);
    };

    while (id.size()) {
        auto [num, i] = *id.rbegin();
        vs[i] = 1;
        id.erase ({num, i});
        if (num == s) {
            is[i] = 1;
            continue;
        }
        int &val = nw[i];
        for (int j = 1; j <= n && val != s; j++) if (i != j && !is[j] && dis[i][j] <= X) {
            if (clock() > 60 * CLOCKS_PER_SEC / 100) return;
            if (val > s) {
                upd (i, j, val - s);
                val = s;
                mx = max (mx, dis[i][j]);
            } else {
                int delta = min (s - val, nw[j]);
                if (delta) {
                    upd (i, j, -delta);
                    val += delta;
                    mx = max (mx, dis[i][j]);
                }
            }
        }
        if (val == s) {
            is[i] = 1;
        }
    }
    int cnt = 0;
    FOR (i, 1, n) cnt += is[i];
    double np = 1 / (power (1.50, cnt) * power (3.00, min (0, mx - x)));
    if (np > point) {
        nk = cnt;
        nx = mx;
        point = np;
        ans = re;
    }

    //debug (cnt, mx, np);
}

void solve() {
    cin >> n >> m >> s >> x;
    FOR (i, 1, n) cin >> w[i], nk += w[i] == x;

    FOR (i, 1, n) {
        fill (dis[i], dis[i] + n + 1, INF);
        dis[i][i] = 0;
    }
    while (m--) {
        int a, b;
        cin >> a >> b;
        dis[a][b] = dis[b][a] = 1;
    }
    FOR (k, 1, n) FOR (i, 1, n) FOR (j, 1, n) dis[i][j] = min (dis[i][j], dis[i][k] + dis[k][j]);

    for (int t = 1; clock() <= 60 * CLOCKS_PER_SEC / 100; t++) {
        work();
    }
    //debug (point);
    cout << nk << ' ' << nx << ' ' << ans.size() << '\n';
    for (auto [a, b, c] : ans) cout << a << ' ' << b << ' ' << c << '\n';
}

int32_t main() {
    Waimai;
    solve();
}


$\text{pB. 自行車歸位 (bicycle)}$

$36/100$:我只有想到 $O(nm)$ 的 $\text{dp}$,可以先排序好後設 $\text{dp}_{i, j}$ 為把 $a_1\sim a_i$ 放到 $b_1\sim b_j$ 的最小值,$\text{dp}_{i, j} = \min (\text{dp}_{i, j - 1}, \text{dp}_{i - 1, j - 1} + \text{abs} (a_i - b_j))$。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int INF = 1e18;
const int SIZE = 2005;

int n, m;
int a[SIZE], b[SIZE];
int dp[SIZE][SIZE], to[SIZE][SIZE];

void solve() {
    cin >> n >> m;
    FOR (i, 1, n) cin >> a[i];
    FOR (i, 1, m) cin >> b[i];
    sort (a + 1, a + n + 1);
    sort (b + 1, b + m + 1);

    FOR (i, 1, n) fill (dp[i], dp[i] + m + 1, INF);
    FOR (i, 1, n) FOR (j, i, m) {
        dp[i][j] = dp[i][j - 1];
        to[i][j] = to[i][j - 1];
        int val = dp[i - 1][j - 1] + abs (a[i] - b[j]);
        if (val < dp[i][j]) {
            dp[i][j] = val;
            to[i][j] = j;
        }
    }
    cout << dp[n][m] << '\n';

    FOR (i, 1, n) FOR (j, 1, m) cout << dp[i][j] << " \n"[j == m];

    vector<pair<int, int>> ans;
    for (int i = n, j = m; i >= 1; i--) {
        int p = to[i][j];
        ans.pb (a[i], b[p]);
        j = p - 1;
    }
    for (auto [x, y] : ans) cout << x << ' ' << y << '\n';
}

int32_t main() {
    Waimai;
    solve();
}


$\text{pC. 卡牌 (card)}$

$100/100$:這題是區間 $\text{dp}$,令 $\text{dp}_{l, r}$ 為 $l\sim r$ 區間的最大值,可以由 $\text{dp}_{l, r - 1}, \text{dp}_{l + 1, r}$ 轉移,複雜度 $O(n^2)$。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int SIZE = 1005;

int n;
int a[SIZE];
int dp[SIZE][SIZE];

void solve() {
    cin >> n;
    FOR (i, 1, n) cin >> a[i], a[i] /= 10;
    FOR (i, 1, n) dp[i][i] = (n + 9) * a[i];
    FOR (len, 2, n) for (int l = 1, r = len; r <= n; l++, r++) {
        dp[l][r] = max (dp[l][r], dp[l][r - 1] + (n - len + 10) * a[r]);
        dp[l][r] = max (dp[l][r], dp[l + 1][r] + (n - len + 10) * a[l]);
    }
    cout << dp[1][n] << '\n';
}

int32_t main() {
    Waimai;
    solve();
}


$\text{pD. 文字編輯器 (editor)}$

$100/100$:可以發現兩個 $x$ 間一定至少要有一個 $+$,所以可以找到中間沒有 $+$ 的兩個 $x$,然後可以計算括號數量用數學推出來 $+$ 要放哪裡。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

//#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int SIZE = 1e6 + 5;

int n;
string s;
int pre[SIZE];
vector<int> p;

void solve() {
    cin >> s;
    n = s.size();
    s = " " + s;
    p.clear();
    FOR (i, 1, n) {
        pre[i] = pre[i - 1];
        if (s[i] == 'x') p.pb (i);
        if (s[i] == '|') pre[i]++;
    }
    FOR (i, 1, p.size() - 1) {
        int l = p[i - 1] + 1, r = p[i] - 1;
        if (r - l + 1 == pre[r] - pre[l - 1]) {
            int num = 1, x = 0, y = 0;
            FOR (j, 1, p[i - 1]) {
                if (s[j] == 'x' || s[j] == '+') num = -num;
                else x += num;
            }
            num = 1;
            for (int j = n; j >= p[i]; j--) {
                if (s[j] == 'x' || s[j] == '+') num = -num;
                else y += num;
            }
            int len = r - l + 1;
            int xl = (x - y + len - 1) / 2;
            debug (x, y, xl);
            s[p[i - 1] + xl + 1] = '+';
            break;
        }
    }
    int num = 1;
    FOR (i, 1, n) {
        if (s[i] == '|') cout << (num == 1 ? '[' : ']');
        else {
            num = -num;
            cout << s[i];
        }
    }
    cout << '\n';
}

int32_t main() {
    Waimai;
    int tt;
    cin >> tt;
    while (tt--) solve();
}


$\text{pE. 齒輪組 (gears)}$

$100/100$:紀錄每個齒輪 $2,3$ 的次數再用連接方式去推下一個就好了。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int SIZE = 25;

int n;
int dir[SIZE], two[SIZE], three[SIZE];
int con[SIZE];
int s2[SIZE], s3[SIZE];

void solve() {
    cin >> n;
    FOR (i, 1, n) {
        int x, y;
        cin >> x >> y;
        if (x == 2) two[i] = y;
        else three[i] = y;
    }
    FOR (i, 2, n) cin >> con[i];
    FOR (i, 2, n) {
        dir[i] = dir[i - 1];
        if (con[i] == 1) dir[i] ^= 1;
    }

    FOR (i, 2, n) {
        if (con[i] == 2) s2[i] = s2[i - 1], s3[i] = s3[i - 1];
        else {
            int x = s2[i - 1] + two[i - 1] - two[i];
            int y = s3[i - 1] + three[i - 1] - three[i];
            s2[i] = x, s3[i] = y;
        }
    }
    cout << (dir[n] == 0 ? 1 : -1) << ' ' << s2[n] << ' ' << s3[n] << '\n';
}

int32_t main() {
    Waimai;
    solve();
}


$\text{pF. 百萬刮刮樂 (scratchcard)}$

$100/100$:把式子移一下可以發現 $(W_x-A_x,W_x-B_x,W_x-C_x)\leq (A_y-W_y,B_y-W_y,C_y-W_y)$,這就很像在問你三維偏序,可以用三個 $\text{vector}$ 存每種錢的 $a,b,c$,然後一組一組去做,要注意同一組時要扣掉自己跟自己的,複雜度 $O(n\times\log^2(n))$。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

//#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int money[3] = {1000000, 2000000, 3000000};
const int INF = 1e9;
const int SIZE = 2e5 + 5;

int n;
ll ans;
vector<int> lis;
vector<tuple<int, int, int>> v[3];
int bit[SIZE];

void upd (int pos, int x) {
    for (; pos; pos -= pos & -pos) bit[pos] += x;
}

int que (int pos) {
    int re = 0;
    for (; pos <= n; pos += pos & -pos) re += bit[pos];
    return re;
}

void divide (vector<tuple<int, int, int, int>> &v, int l, int r) {
    if (l >= r) return;

    r -= l, l = 0;

    int mid = (l + r) / 2;
    vector<tuple<int, int, int, int>> vl, vr;
    FOR (i, 0, mid) vl.pb (v[i]);
    FOR (i, mid + 1, v.size() - 1) vr.pb (v[i]);
    v.clear();
    divide (vl, l, mid);
    divide (vr, mid + 1, r);

    int p1 = 0, p2 = 0;
    while (p1 < vl.size() || p2 < vr.size()) {
        int ty;
        if (p2 == vr.size()) ty = 0;
        else if (p1 == vl.size()) ty = 1;
        else if (get<0> (vl[p1]) >= get<0> (vr[p2])) ty = 0;
        else ty = 1;

        if (ty == 0) {
            auto [b, c, t, a] = vl[p1];
            v.pb (vl[p1]);
            p1++;
            if (t == 1) {
                int p = lower_bound (lis.begin(), lis.end(), c) - lis.begin() + 1;
                upd (p, 1);
            }
        } else {
            auto [b, c, t, a] = vr[p2];
            v.pb (vr[p2]);
            p2++;
            if (t == 0) {
                int p = lower_bound (lis.begin(), lis.end(), c) - lis.begin() + 1;
                ans += que (p);
            }
        }
    }
    FOR (i, 0, vl.size() - 1) {
        auto [b, c, t, a] = vl[i];
        if (t == 1) {
            int p = lower_bound (lis.begin(), lis.end(), c) - lis.begin() + 1;
            upd (p, -1);
        }
    }
}

bool ok (int g1, int g2) {
    ans = 0;
    if (g1 == g2) {
        for (auto [a, b, c] : v[g1]) {
            if (min ({a, b, c}) >= money[g1]) ans--;
        }
    }
    vector<tuple<int, int, int, int>> vv;
    int w = money[g1];
    for (auto [a, b, c] : v[g1]) {
        vv.pb (w - b, w - c, 0, w - a);
    }
    w = money[g2];
    lis.clear();
    for (auto [a, b, c] : v[g2]) {
        vv.pb (b - w, c - w, 1, a - w);
        lis.pb (c - w);
    }
    sort (vv.begin(), vv.end(), [] (auto A, auto B) {
        return get<3> (A) != get<3> (B) ? get<3> (A) > get<3> (B) : get<2> (A) > get<2> (B);
    });
    sort (lis.begin(), lis.end());
    lis.erase (unique (lis.begin(), lis.end()), lis.end());
    divide (vv, 0, (int) vv.size() - 1);
    return ans > 0;
}

const int MAX = 1e6;

void solve() {
    cin >> n;
    FOR (t, 1, n) {
        int w, a, b, c;
        int da, db, dc;
        cin >> w >> a >> b >> c;
        int p;
        FOR (i, 0, 2) if (w == money[i]) p = i;
        v[p].pb (a, b, c);
    }
    set<int> s;
    FOR (i, 0, 2) FOR (j, i, 2) {
        if (ok (i, j)) s.insert (money[i] + money[j]);
    }
    cout << s.size() << '\n';
    for (int x : s) cout << x << '\n';
}

int32_t main() {
    Waimai;
    solve();
}


$\text{pG. 算樹 (tree)}$

$27/100$:可以發現 $3\sim n$ 的排列一定可以做出來,所以直接計算階乘就好了。

$51/100$:暴力枚舉 $\text{Prufer code}$,我的做法是用一個 $\text{pq}$ 找目前最小葉節點,複雜度 $O(n^{n-1}\times\log(n))$。

$100/100$:我最後發現每個數字在 $\text{Prufer code}$ 裡出現的次數會是它的度數 $-1$,而且一定可以構造出一棵樹,所以可以用到排列組合和 $ \frac{(\sum a_i+\sum b_i)!}{\prod a_i!\prod b_i!}=\frac{(\sum a_i)!}{\prod a_i!}\times\frac{(\sum b_i)!}{\prod b_i!}\times C_{\sum a_i}^{\sum a_i+\sum b_i}$,先把前綴、後綴和積建好,之後枚舉數字,就可以知道現在該選哪個,複雜度 $O(n^2)$。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int INF = 2e9;
const int SIZE = 1005;

int n, k;
int d[SIZE];
int C[SIZE][SIZE];
int pre[SIZE], suf[SIZE];
int prep[SIZE], sufp[SIZE];

void solve() {
    cin >> n >> k;
    FOR (i, 1, n) cin >> d[i];
    FOR (i, 1, n) d[i]--;
    C[0][0] = 1;
    FOR (i, 1, n) {
        C[i][0] = 1;
        FOR (j, 1, i) C[i][j] = min (INF, C[i - 1][j - 1] + C[i - 1][j]);
    }

    k--;
    int pro = 1;
    for (int i = 1, m = 0; i <= n; i++) {
        m += d[i];
        pro = min (INF, pro * C[m][d[i]]);
    }
    debug (k, pro);
    if (k >= pro) {
        cout << "-1\n";
        return;
    }

    vector<int> ans;
    FOR (t, 1, n - 2) {
        prep[0] = sufp[n + 1] = 1;
        FOR (i, 1, n) {
            pre[i] = pre[i - 1] + d[i];
            prep[i] = min (INF, prep[i - 1] * C[pre[i]][d[i]]);
        }
        for (int i = n; i >= 1; i--) {
            suf[i] = suf[i + 1] + d[i];
            sufp[i] = min (INF, sufp[i + 1] * C[suf[i]][d[i]]);
        }
        bool f = 0;
        FOR (i, 1, n) if (d[i]) {
            int val = min (INF, prep[i - 1] * sufp[i + 1]);
            val = min (INF, val * C[pre[i - 1] + suf[i + 1]][pre[i - 1]]);
            val = min (INF, val * C[n - 2 - t][pre[i - 1] + suf[i + 1]]);
            debug (i, k, val);
            if (k >= val) k -= val;
            else {
                debug (t, i);
                d[i]--;
                ans.pb (i);
                f = 1;
                break;
            }
        }
        if (!f) {
            cout << "-1\n";
            return;
        }
    }
    for (int x : ans) cout << x << '\n';
}

int32_t main() {
    Waimai;
    solve();
}


$\text{pH. 城市規劃 (ussr)}$

$4/100$:可以直接把每個點排成一圈,然後連左右的就好了。

$35/100$:我這樣子構,挑出四個點放到外側,然後內側放兩行。


$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int SIZE = 105;

int n, k;

void solve() {
    cin >> n >> k;
    if (k == 0) {
        if (n == 1) {
            cout << "0 0\n\n";
        } else {
            cout << "-1\n";
        }
        return;
    }
    if (k >= n || n * k % 2 != 0) {
        cout << "-1\n";
        return;
    }
    if (n == 2 && k == 1) {
        cout << "0 0\n";
        cout << "1 0\n";
        cout << "2\n";
        cout << "1\n";
        return;
    }
    if (k == 1) {
        cout << "-1\n";
        return;
    }
    if (k == 2) {
        FOR (i, 1, n - 1) cout << "0 " << i << '\n';
        cout << "1 " << n << '\n';
        FOR (i, 1, n) {
            int l = i - 1, r = i + 1;
            if (l <= 0) l += n;
            if (r > n) r -= n;
            cout << l << ' ' << r << '\n';
        }
        return;
    }
    if (n == 4 && k == 3) {
        cout << "0 0\n1 1\n0 2\n10 2\n";
        FOR (i, 1, n) {
            FOR (j, 1, n) if (i != j) cout << j << ' ';
            cout << '\n';
        }
        return;
    }
    if (k == 3) {
        cout << "3 1\n";
        FOR (i, 2, n / 2 - 1) cout << "2 " << i << '\n';
        cout << "3 " << n / 2 << '\n';
        cout << "0 " << 1 << '\n';
        FOR (i, n / 2 + 2, n - 1) cout << "1 " << i - n / 2 << '\n';
        cout << "0 " << n / 2 << '\n';

        cout << "2 " << n / 2 << ' ' << n / 2 + 1 << '\n';
        FOR (i, 2, n / 2 - 1) cout << i - 1 << ' ' << i + 1 << ' ' << i + n / 2 << '\n';
        cout << n / 2 - 1 << ' ' << "1 " << n << '\n';
        cout << n / 2 + 2 << ' ' << "1 " << n << '\n';
        FOR (i, n / 2 + 2, n - 1) cout << i - 1 << ' ' << i + 1 << ' ' << i - n / 2 << '\n';
        cout << n - 1 << ' ' << n / 2 + 1 << ' ' << n / 2 << '\n';
        return;
    }
}

int32_t main() {
    Waimai;
    solve();
}


$\text{pI. 聖誕燈飾 (xmas)}$

$100/100$:直接做就好,複雜度 $O(n\times\log(n))$。

$\text{Code:}$

#pragma GCC optimize("O3,unroll-loops")
#pragma GCC target("avx,avx2,popcnt,sse4,abm")
#include <bits/stdc++.h>
using namespace std;

#ifdef WAIMAI
#define debug(HEHE...) cout<<"["<<#HEHE<<"] : ",dout(HEHE)
void dout(){cout<<'\n';}
template<typename T,typename...U>
void dout(T t,U...u){cout<<t<<(sizeof...(u)?", ":""),dout(u...);}
#else
#define debug(...) 7122
#endif

//#define int long long
#define ll long long
#define Waimai ios::sync_with_stdio(false),cin.tie(0)
#define FOR(x,a,b) for(int x=a,I=b;x<=b;x++)
#define pb emplace_back
#define F first
#define S second

const int SIZE = 1e6 + 5;

int n, m;
int a[SIZE], b[SIZE];

void solve() {
    cin >> n >> m;
    FOR (i, 1, n) cin >> a[i], a[i]--;
    FOR (i, 1, n) cin >> b[i], b[i]--;
    FOR (i, 1, n) {
        int add = (b[i] - a[i] + m) % m;
        cout << add << '\n';
        for (int j = i; j <= n; j += i) {
            a[j] += add;
            if (a[j] >= m) a[j] -= m;
        }
    }
}

int32_t main() {
    Waimai;
    solve();
}


心得:我前面好像很快就把簡單題寫好了,看到 $\text{pF}$,知道是三維偏序,但是 $\text{debug}$ 很久,那裡的程式執行視窗我不知道怎麼貼上東西,導致要一直自己手打輸入。再來我一開始以為 $\text{pD,pG}$ 會是很難的題,我到比賽後半段才去碰它們,$\text{pD}$ 觀察一下後發現超好寫,$\text{pG}$ 只有先寫出第二子題,然後 $\text{pA}$ 花了滿久時間去寫,但一分都沒拿到。最後我大概在 $622$ 分的時候就想說我拿不到分數了,所以我就出去吃一下東西,回來看到 $\text{pG}$,發現一個東西,想一想就突然知道題目要問什麼了,然後在前幾年的 $\text{TOI}$ 初選有考過類似的東西,我大概知道要怎麼寫,可是這時時間只剩下 $20$ 分鐘了,我要把一堆數學的東西刻好,過程中錯誤一堆,但很神奇的是一下就找到錯在哪裡了,更神奇的是竟然過範測了,這時加上比賽延長的 $2$ 分鐘,我剩的時間只剩下 $2$ 分多鐘了,很驚險的是上傳之後就過了,然後上傳的時間是 $4:59:11$。賽後聽別人說 $\text{pH}$ 是奇怪數學題,然後 $\text{pA}$ 沒有人會做,$\text{pB}$ 好像沒想像的那麼難。

最後我拿到 $671$ 分 (計分板),並列三個第一,不過我是三個裡最晚拿到分數的,最終結果是一等獎,我有點不敢相信,因為我去年連北市賽三等獎都沒有。然後進了前十名代表不用考初選了,好開心。


的分享就到這裡結束了,如果喜歡我的 $\text{Blog}$ 歡迎追蹤!

留言

熱門文章