T1: tcdr

模拟

代码实现
#include <bits/stdc++.h>

using namespace std;

int main() {
    string s;
    cin >> s;
    
    erase_if(s, [](char c) { return ranges::count("aeiou", c); });
    
    cout << s << '\n';
    
    return 0;
}

T2:The Middle Day

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n;
    cin >> n;
    
    vector<int> d(n);
    rep(i, n) cin >> d[i];
    
    int tot = reduce(d.begin(), d.end());
    int k = (tot+1)/2;
    rep(i, n) {
        if (k <= d[i]) {
            cout << i+1 << ' ' << k << '\n';
            break;
        }
        k -= d[i];
    }
    
    return 0;
}

T3:Flavors

显然必选最美味的冰激凌,然后枚举另一个即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n;
    cin >> n;
    
    vector<int> f(n), s(n);
    rep(i, n) cin >> f[i] >> s[i];
    
    int a = 0, ai = -1;
    rep(i, n) {
        if (a < s[i]) {
            a = s[i];
            ai = i;
        }
    }
    
    int b = 0;
    rep(i, n) {
        if (i == ai) continue;
        if (f[i] == f[ai]) b = max(b, s[i]/2);
        else b = max(b, s[i]);
    }
    
    int ans = a+b;
    cout << ans << '\n';
    
    return 0;
}

T4:Magical Cookies

维护每个字符在当前行/当前列中都出现了多少次,并在每次操作中进行更新,每次检查的复杂度就是 \(\mathcal{O}(26(H+W))\)

注意:只有剩下的某行/某列的曲奇颜色都相同,才执行删除操作

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

int main() {
    int h, w;
    cin >> h >> w;
    
    vector<string> c(h);
    rep(i, h) cin >> c[i];
    
    vector a(h, vector<int>(w));
    rep(i, h)rep(j, w) a[i][j] = c[i][j]-'a';
    
    const int m = 26;
    vector row(h, vector<int>(m));
    vector col(w, vector<int>(m));
    rep(i, h)rep(j, w) {
        row[i][a[i][j]]++;
        col[j][a[i][j]]++;
    }
    vector<bool> row_deleted(h);
    vector<bool> col_deleted(w);
    
    auto toDelete = [&](vector<int> x) {
        int tot = 0, k = 0;
        rep(j, m) {
            tot += x[j];
            if (x[j]) k++;
        }
        return tot >= 2 and k == 1; 
    };
    auto del = [&](int i, int j) {
        if (row_deleted[i] or col_deleted[j]) return;
        row[i][a[i][j]]--;
        col[j][a[i][j]]--;
    };
    
    bool upd = true;
    while (upd) {
        upd = false;
        vector<int> del_row, del_col;
        rep(i, h) {
            if (row_deleted[i]) continue;
            if (toDelete(row[i])) del_row.push_back(i);
        }
        rep(j, w) {
            if (col_deleted[j]) continue;
            if (toDelete(col[j])) del_col.push_back(j);
        }
        for (int i : del_row) {
            rep(j, w) del(i, j);
            row_deleted[i] = true;
            upd = true;
        }
        for (int j : del_col) {
            rep(i, h) del(i, j);
            col_deleted[j] = true;
            upd = true;
        }
    }
    
    int ans = 0;
    rep(i, h)rep(j, w) {
        if (row_deleted[i] or col_deleted[j]) continue;
        ans++;
    }
    
    cout << ans << '\n';
    
    return 0;
}

T5:Prerequisites

\(\operatorname{dfs}\)

突然开始读第一本书,如果有不明白的地方就回到上一本书

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

int main() {
    int n;
    cin >> n;
    
    vector<vector<int>> to(n);
    rep(i, n) {
        int c;
        cin >> c;
        rep(j, c) {
            int p;
            cin >> p;
            to[i].push_back(p-1);
        }
    }
    
    vector<int> ans;
    vector<bool> used(n);
    auto dfs = [&](auto f, int v) -> void {
        used[v] = true;
        for (int u : to[v]) {
            if (used[u]) continue;
            f(f, u);
        }
        ans.push_back(v);
    };
    dfs(dfs, 0);
    ans.pop_back();
    
    for (int v : ans) cout << v+1 << ' ';
    
    return 0;
}

T6:Shortcuts

dp[i][j] 表示到达检查点 \(i\) 处已经跳过 \(j\) 个检查点的最小移动距离
但时间复杂度是 \(\mathcal{O}(n^3)\)

即使通过所有的检查点,距离也只有 \(3 \times 10^8\),所以考虑罚款比这个更大的情况是没有用的!也就是说,只需考虑跳过的检查点不超过 \(20\) 个时,可以在 \(\mathcal{O}(20^2 n)\) 时间内解决!

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;

inline void chmin(double& a, double b) { if (a > b) a = b; }

int main() {
    int n;
    cin >> n;
    
    vector<int> x(n), y(n);
    rep(i, n) cin >> x[i] >> y[i];
    
    const int m = 20;
    auto dist = [&](int i, int j) {
        int dx = x[i]-x[j], dy = y[i]-y[j];
        return sqrt(dx*dx+dy*dy);
    };
    
    const double INF = 1e18;
    vector dp(n, vector<double>(m, INF));
    dp[0][0] = 0;
    rep(i, n)rep(j, m) {
        for (int ni = i+1, nj = j; ni < n and nj < m; ++ni, ++nj) {
            chmin(dp[ni][nj], dp[i][j]+dist(i, ni));
        }
    }
    
    double ans = INF;
    rep(j, m) chmin(ans, dp[n-1][j]+(1<<j>>1));
    
    printf("%.10f\n", ans);

    return 0;
}

T7:Ai + Bj + Ck = X (1 <= i, j, k <= N)

可以枚举 \(k\),然后就变成了求满足 \(Ai+Bj=Y\) 的解 \((i, j)\) 的个数的问题,而这个问题是 \(\operatorname{exgcd}\) 板题

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using ll = long long;

// ai+bj=g
ll exgcd(ll a, ll b, ll& i, ll& j) {
    if (b == 0) { i = 1; j = 0; return a; }
    ll p = a/b, g = exgcd(b, a-b*p, j, i);
    j -= p*i;
    return g;
}

int main() {
	int n;
	cin >> n;
	
	ll A, B, C, X;
	cin >> A >> B >> C >> X;
	X -= A+B+C;
	
	auto f2 = [&](ll x) -> ll {
	    if (x < 0) return 0;
	    ll i, j;
	    ll g = exgcd(A, B, i, j);
	    if (x%g) return 0;
	    x /= g;
	    ll a = A/g, b = B/g;
	    // ai+bj=1
	    i = (i+b)*(x%b)%b;
	    j = (x-i*a)/b;
	    // a(i+bk)+b(j+ak)=x 
	    // 0 <= i+bk, 0 <= j-ak (0 <= i < b)
	    // -i/b <= k <= j/a (-1 < -i/b <= 0)
	    if (j < 0) return 0;
	    return j/a+1;
	};
	
	auto f = [&](ll x) {
	    ll res = f2(x);
	    res -= f2(x-A*n);
	    res -= f2(x-B*n);
	    res += f2(x-A*n-B*n);
	    return res;
	};
	
	ll ans = 0;
	rep(k, n) {
	    ans += f(X);
	    X -= C;
	}
	
	cout << ans << '\n';
	
	return 0;
}