1. 程式人生 > 其它 >AtCoder Beginner Contest 222 覆盤

AtCoder Beginner Contest 222 覆盤

A. Four Digits

一遍 AC。

int n;

int main() {
    scanf("%d", &n);
    std::string str = std::to_string(n);
    while (str.size() != 4) str = '0' + str;
    printf("%s\n", str.c_str());
    return 0;
}

B. Failing Grade

一遍 AC。

int n, p;

int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n >> p;
    int ans = 0;
    rep (i, 1, n) {
        int x; cin >> x;
        ans += (x < p);
    }
    cout << ans << endl;
    return 0;
}

C. Swiss-System Tournament

機房裡吵得讀不下去題,拖到後面才做的。

WA 了 1 發,先是讀錯題,然後又打了好幾個 typo。

#錯誤警示:拒絕打錯微小字元,比如 ij
#錯誤警示:讀好題目的資料範圍資訊,比如 \(2n\) 個人需要開兩倍陣列。

const int MAXN = 50 + 10;
const int MAXM = 100 + 10;

int judge(int id1, char s1, int id2, char s2) {
    if (s1 == s2) return 2;
    if (s1 == 'G') return s2 == 'C';
    if (s1 == 'C') return s2 == 'P';
    /* s1 == 'P' */ return s2 == 'G';
}

int n, m;
char give[MAXN * 2][MAXM];
int rank[MAXN * 2]; // do not forget
struct ND { int val, id; } wins[MAXN * 2];

bool cmp(ND x, ND y) { return x.val == y.val ? x.id < y.id : x.val > y.val; }
bool cmp2(ND x, ND y) { return x.id < y.id; }

int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n >> m;
    rep (i, 1, 2 * n) { cin >> (give[i] + 1); rank[i] = i; wins[i].id = i; }
    rep (i, 1, m) {
        // typo: i -> j
        std::sort(wins + 1, wins + 1 + 2 * n, cmp2);
        rep (j, 1, n) {
            int s1 = rank[j * 2 - 1], s2 = rank[j * 2];
            if (judge(s1, give[s1][i], s2, give[s2][i]) == 2) continue;
            if (judge(s1, give[s1][i], s2, give[s2][i])) ++wins[s1].val;
            else ++wins[s2].val;
        } std::sort(wins + 1, wins + 1 + 2 * n, cmp);
        rep (j, 1, 2 * n) rank[j] = wins[j].id;
        // rep (x, 1, 2 * n) cout << rank[x] << ' ';
        // cout << endl;
    }
    rep (i, 1, 2 * n) cout << rank[i] << endl;
    return 0;
}

D. Between Two Arrays

f[i][j] 表示考慮前 i 個限制,第 i 次選的數是 j 的方案數。搞一個字首和優化轉移即可。

一遍 AC。

const int MAXN = 3000 + 10;
const int MAXS = 3000;
const int HA = 998244353;

int n, aa[MAXN], bb[MAXN];
int dp[MAXN][MAXN];
lli sumdp[MAXN][MAXN]; // sum of dp[i][1~j]

int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    rep (i, 1, n) cin >> aa[i];
    rep (i, 1, n) cin >> bb[i];
    rep (i, 1, 1) {
        rep (x, aa[i], bb[i]) dp[i][x] = 1;
        rep (x, aa[i], MAXS) (sumdp[i][x] = sumdp[i][x - 1] + dp[i][x]) %= HA;
    }
    rep (i, 2, n) {
        rep (j, aa[i], bb[i]) {
            dp[i][j] = sumdp[i - 1][j];
        } rep (j, aa[i], MAXS) (sumdp[i][j] = sumdp[i][j - 1] + dp[i][j]) %= HA;
    }
    cout << sumdp[n][bb[n]] << endl;
    return 0;
}

E. Red and Blue Tree

首先可以算出每條邊被經過的次數 \(c_i\),然後就可以 DP 了。

最開始想的是 f[i][j] 表示前 \(i\) 條邊,\(R - B = j\) 的方案數,但是時空複雜度是 \(O(N|K|)\) 的,可不可以滾動陣列沒試過,總覺得應該過不去就沒寫。

題解又做了一步轉化:設 \(S = \sum c_i\),於是題目轉化成了選擇一些 \(c_i\) 求和得到 \(\frac{S + K}{2}\) 的方案數(\(S + K < 0\) 或是偶數的情況即是無解)。這就是一個揹包板子了。

時間複雜度還是 \(O(N|K|)\) 居然能過 離譜。

const int MAXN = 1000 + 10;
const int MAXM = 100000 + 10;
const int HA = 998244353;

int n, m, k;
struct E { int v, id; };
std::vector<E> G[MAXN];

int cnt[MAXN];
int dp[MAXM];

bool dfs(int u, int fa, int end) {
    if (u == end) return true;
    bool ans = false;
    forall (G[u], i) {
        int v = G[u][i].v, id = G[u][i].id;
        if (v == fa) continue;
        if (dfs(v, u, end)) {++cnt[id]; ans = true;}
    } return ans;
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n >> m >> k;
    std::vector<int> vc;
    rep (i, 1, m) { int x; cin >> x; vc.push_back(x); }
    rep (i, 1, n - 1) {
        int u, v; cin >> u >> v;
        G[u].push_back({v, i}); G[v].push_back({u, i});
    }
    rep (i, 1, m - 1) {
        dfs(vc[i - 1], 0, vc[i]);
    }
    int S = 0;
    rep (i, 1, n - 1) {
        S += cnt[i];
    }
    if ((S + k) < 0 || ((S + k) & 1)) {
        cout << 0 << endl; return 0;
    }
    dp[0] = 1;
    for (int i = 1; i <= n - 1; ++i) {
        for (int j = MAXM - 10; j >= cnt[i]; --j) {
            (dp[j] += dp[j - cnt[i]]) %= HA;
        }
    } cout << dp[(S + k) >> 1] << endl;
    return 0;
}

F. Expensive Expense

樹的直徑端點。

後悔考場上沒開這題。

交了好幾發沒過,一查發現是 disdist 寫 typo 了。

#錯誤警示:寫程式碼專注一點,不要純靠肌肉記憶,因為你肌肉記憶的和這題可能有些出入。

const int MAXN = 200000 + 10;
int n;
lli val[MAXN];

struct E { int v; lli val; }; std::vector<E> G[MAXN];
bool operator < (const E &x, const E &y) {
    return x.val > y.val;
}

lli dist[MAXN];
void sp(int st, lli *dis) {
    for (int i = 1; i <= n; ++i) dis[i] = (1ll << 62); 
    std::priority_queue<E> q;
    static bool vis[MAXN]; memset(vis, 0, sizeof vis);
    q.push({st, dis[st] = 0});
    while (!q.empty()) {
        int u = q.top().v; q.pop();
        if (vis[u]) continue;
        vis[u] = true;
        forall (G[u], i) {
            int v = G[u][i].v, w = G[u][i].val;
            // typo: dist dis
            if (dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                q.push({v, dis[v]});
            }
        }
    }
}
int main() {
    std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    rep (i, 1, n - 1) {
        int u, v, w; cin >> u >> v >> w;
        G[u].push_back({v, w}); G[v].push_back({u, w});
    }
    rep (i, 1, n) cin >> val[i];

    int s1 = 0;
    sp(1, dist);
    for (int i = 1; i <= n; ++i) {
        if (dist[s1] + val[s1] < dist[i] + val[i]) {
            s1 = i;
        }
    }
    sp(s1, dist);
    int s2 = 0;
    for (int i = 1; i <= n; ++i) {
        if (s1 == i) continue;
        if (dist[s2] + val[s2] < dist[i] + val[i]) {
            s2 = i;
        }
    }
    // DEBUG(s1); DEBUG(s2);
    static lli dist2[MAXN];
    sp(s2, dist2);
    for (int i = 1; i <= n; ++i) {
        // DEBUG(dist[i]); DEBUG(dist2[i]);
        if (i == s1) cout << dist[s2] + val[s2] << endl;
        else if (i == s2) cout << dist2[s1] + val[s1] << endl;
        else {
            if (dist2[i] + val[s2] > dist[i] + val[s1]) cout << dist2[i] + val[s2] << endl;
            else cout << dist[i] + val[s1] << endl;
        }
    }
    return 0;
}