T1:First ABC

模拟

代码实现
n = int(input())
s = input()

A = B = C = False
for i in range(n):
    if s[i] == 'A': A = True
    if s[i] == 'B': B = True
    if s[i] == 'C': C = True
    if A and B and C: 
        exit(print(i+1))

T2:Vacation Together

暴力

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

using namespace std;

int main() {
    int n, d;
    cin >> n >> d;
    
    vector<string> s(n);
    rep(i, n) cin >> s[i];
    
    string t;
    rep(i, d) {
        bool ok = true;
        rep(j, n) if (s[j][i] == 'x') ok = false;
        if (ok) t += 'o'; else t += 'x';
    }
    
    int ans = 0, now = 0;
    rep(i, d) {
        if (t[i] == 'o') now++; else now = 0;
        ans = max(ans, now);
    }
    
    cout << ans << '\n';
    
    return 0;
}

T3:Find it!

注意到无论从哪个点开始搜,最终都会走到环里,所以当第一次走到已经走过的点时可以再走一圈

代码实现
#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> a(n+1);
    rep(i, n) cin >> a[i+1];
    
    vector<int> id(n+1);
    int k = 1;
    int v = 1;
    while (id[v] == 0) {
        id[v] = k; k++;
        v = a[v];
    }
    
    vector<int> ans;
    int len = k-id[v];
    rep(i, len) {
        ans.push_back(v);
        v = a[v];
    }
    
    cout << len << '\n';
    for (int v : ans) cout << v << ' ';
    
    return 0;
}

T4:Grid Ice Floor

当前停在哪个方格 作为状态,沿着上下左右哪个方向进行 \(\operatorname{bfs}\),同时记录下滑行途中经过的方格以及最终停在的方格!

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

using namespace std;
using P = pair<int, int>;

const int di[] = {-1, 0, 1, 0};
const int dj[] = {0, 1, 0, -1};

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<string> s(n);
    rep(i, n) cin >> s[i];
    
    vector used(n, vector<bool>(m));
    vector passed(n, vector<bool>(m));
    queue<P> q;
    q.emplace(1, 1); 
    passed[1][1] = used[1][1] = true;
    while (q.size()) {
        auto [i, j] = q.front(); q.pop();
        rep(v, 4) {
            int ni = i, nj = j;
            while (s[ni][nj] == '.') {
                passed[ni][nj] = true;
                ni += di[v]; nj += dj[v];
            }
            ni -= di[v]; nj -= dj[v];
            if (used[ni][nj]) continue;
            used[ni][nj] = true;
            q.emplace(ni, nj);
        }
    }
    
    int ans = 0;
    rep(i, n)rep(j, m) if (passed[i][j]) ans++;
    
    cout << ans << '\n';
    
    return 0;
}

T5:Defect-free Squares

考虑将有洞的格子标记为 \(0\),其他格子标记为 \(1\)

dp[i][j] 表示以方格 \((i, j)\) 为右下角且仅包含 \(1\) 的正方形的边长的最大值

答案为 \(\sum dp[i][j]\)

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

using namespace std;
using P = pair<int, int>;
using ll = long long;

int main() {
    int h, w, n;
    cin >> h >> w >> n;
    
    vector dp(h, vector<int>(w, 1));
    rep(i, n) {
        int a, b;
        cin >> a >> b;
        --a; --b;
        dp[a][b] = 0;
    }
    
    rep(i, h)rep(j, w) {
        if (dp[i][j] == 0) continue;
        if (i == 0 or j == 0) continue;
        dp[i][j] = min({dp[i-1][j], dp[i][j-1], dp[i-1][j-1]})+1;
    }
    
    ll ans = 0;
    rep(i, h)rep(j, w) ans += dp[i][j];
    cout << ans << '\n';
    
    return 0;
}

T6:Yet Another Grid Task

dp[j][i] 表示在前 \(j\) 列中最后一列的染黑格子的高度为 \(i\) 的合法方案数

然后用前缀和优化即可

代码实现
#include <bits/stdc++.h>
#if __has_include(<atcoder/all>)
#include <atcoder/all>
using namespace atcoder;
#endif
#define rep(i, n) for (int i = 0; i < (n); ++i)

using namespace std;
using mint = modint998244353;

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<int> v(m);
    rep(i, n) {
        string s;
        cin >> s;
        rep(j, m) if (s[j] == '#') v[j] = max(v[j], n-i);
    }
    
    vector dp(m+1, vector<mint>(n+1));
    for (int i = v[0]; i <= n; ++i) dp[0][i] = 1;
    rep(j, m) {
        mint now = dp[j][0];
        rep(i, n+1) {
            if (i < n) now += dp[j][i+1];
            if (i >= v[j+1]) dp[j+1][i] = now;
        }
    }
    
    mint ans = dp[m][n];
    cout << ans.val() << '\n';
    
    return 0;
}

T7:One More Grid Task

可以考虑枚举矩形的上下边界,对每列元素进行求最小值以及求和,这样就转化成了一维的版本,对于一维的版本只需使用单调栈来维护即可
总的时间复杂度为 \(\mathcal{O}(N^2M)\)

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

using namespace std;
using ll = long long;

struct Dat {
    int x, y;
    Dat(int x=0, int y=0): x(x), y(y) {}
};

ll f(vector<int> l, vector<int> s) {
    l.push_back(0);
    s.push_back(0);
    int n = l.size();
    stack<Dat> st;
    ll res = 0;
    int x = 0;
    rep(i, n) {
        int nx = x;
        while (st.size() and st.top().y >= l[i]) {
            Dat d = st.top(); st.pop();
            res = max(res, ll(x-d.x)*d.y);
            nx = d.x;
        }
        st.emplace(nx, l[i]);
        x += s[i];
    }
    return res;
} 

int main() {
    int n, m;
    cin >> n >> m;
    
    vector a(n, vector<int>(m));
    rep(i, n)rep(j, m) cin >> a[i][j];
    
    const int INF = 1001001001;
    ll ans = 0;
    rep(si, n) {
        vector<int> l(m, INF), s(m);
        for (int ti = si; ti < n; ++ti) {
            rep(j, m) {
                l[j] = min(l[j], a[ti][j]);
                s[j] += a[ti][j];
            }
            ans = max(ans, f(l, s));
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}