T1:Weekly Records

模拟

代码实现
n = int(input())
a = list(map(int, input().split()))

ans = [0]*n
for i in range(n):
    for j in range(i*7, (i+1)*7):
        ans[i] += a[j]
        
for x in ans:
    print(x, end=' ')

T2:racecar

模拟

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

using namespace std;

bool isPalindrome(string s) {
    string t = s;
    reverse(t.begin(), t.end());
    return s == t;
}

int main() {
    int n;
    cin >> n;
    
    vector<string> s(n);
    rep(i, n) cin >> s[i];
    
    rep(i, n)rep(j, n) {
        if (i == j) continue;
        string t = s[i]+s[j];
        if (isPalindrome(t)) {
            puts("Yes");
            return 0;
        }
    }
    
    puts("No");
    
    return 0;
}

T3:Ideal Sheet

暴力枚举两张图的摆放位置即可

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

using namespace std;

struct Sheet {
    int h, w;
    vector<string> s;
    void input() {
        cin >> h >> w;
        s = vector<string>(h);
        rep(i, h) cin >> s[i];
    }
    void clear() {
        rep(i, h)rep(j, w) s[i][j] = '.';
    }
    bool copy(Sheet a, int di, int dj) {
        rep(i, a.h)rep(j, a.w) {
            if (a.s[i][j] == '.') continue;
            int ni = i+di, nj = j+dj;
            if (ni < 0 or ni >= h or nj < 0 or nj >= w) return false;
            s[ni][nj] = a.s[i][j];
        }
        return true;
    }
};

int main() {
    Sheet a, b, x;
    a.input();
    b.input();
    x.input();
    
    for (int ai = -a.h; ai < x.h; ++ai) {
        for (int aj = -a.w; aj < x.w; ++aj) {
            for (int bi = -b.h; bi < x.h; ++bi) {
                for (int bj = -b.w; bj < x.w; ++bj) {
                    Sheet y = x;
                    y.clear();
                    if (!y.copy(a, ai, aj)) continue;
                    if (!y.copy(b, bi, bj)) continue;
                    if (x.s == y.s) {
                        puts("Yes");
                        return 0;
                    }
                }
            }   
        }
    }
    
    puts("No");
    
    return 0;
}

T4:Mismatched Parentheses

可以根据 ( 的出现位置将字符串进行分割,即每个分割子串以 ( 的前一个字符结尾,可以用一个栈来维护所有的分割子串。
然后扫描字符串 \(s\),如果遇到 ),此时如果栈里有元素的话,就弹出栈顶元素。

时间复杂度为 \(O(n)\)

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

using namespace std;

int main() {
    int n;
    string s;
    cin >> n >> s;
    
    vector<string> st;
    st.push_back("");
    for (char c : s) {
        if (c == '(') {
            st.push_back("(");
        }
        else if (c == ')') {
            if (st.size() == 1) st.back() += c;
            else st.pop_back();
        }
        else {
            st.back() += c;
        }
    }
    
    string ans;
    for (string t : st) ans += t;
    
    cout << ans << '\n';
    
    return 0;
}

T5:Distinct Adjacent

不妨固定分配给第一个人的数,然后进行 \(dp\)

dp[i][0/1] 表示在前 \(i\) 个人中给最后一个人分配和第一个人相同(不同)的数的合法方案数

最后的答案为 \(dp[n][1]*m\)

时间复杂度为 \(\mathcal{O}(n)\)

代码实现
#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 dp(n, vector<mint>(2));
    dp[0][0] = 1;
    for (int i = 1; i < n; ++i) {
        dp[i][0] = dp[i-1][1];
        dp[i][1] = dp[i-1][0]*(m-1);
        dp[i][1] += dp[i-1][1]*(m-2);
    }
    
    mint ans = dp[n-1][1]*m;
    cout << ans.val() << '\n';
    
    return 0;
}

T6:Virus 2

对每个点 \(i\) 维护好它的感染日 \(d_i\) 以及感染日前一天的所有被感染点到点 \(i\) 的最短距离 \(e_i\),然后跑 \(\operatorname{Dijkstra}\)
问题是传播要延迟到第二天以后,但如果在给定 \(d\)\(w\) 的前提下,提前预处理出在 \(d\) 天以后 \(X_j \geqslant w\) 的最早的一天,就能及时找到它。
可以用倍增或者线段树上二分来优化

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

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

inline void chmax(int& x, int y) { if (x < y) x = y; }

struct Edge {
    int to, w;
    Edge(int to=0, int w=0): to(to), w(w) {}
};

int main() {
    int n, m;
    cin >> n >> m;
    
    vector<vector<Edge>> g(n);
    rep(i, m) {
        int a, b, w;
        cin >> a >> b >> w;
        --a; --b;
        g[a].emplace_back(b, w);
        g[b].emplace_back(a, w);
    }
    
    const int INF = 1001001001;
    vector<P> dist(n, P(INF, INF));
    priority_queue<PP, vector<PP>, greater<PP>> q;
    
    auto push = [&](int v, P x) {
        if (dist[v] <= x) return;
        dist[v] = x;
        q.emplace(x, v);
    };
    
    {
        int k;
        cin >> k;
        rep(i, k) {
            int a;
            cin >> a;
            --a;
            push(a, P(-1, 0));
        }
    }
    
    int D;
    cin >> D;
    vector<int> x(D);
    rep(i, D) cin >> x[i];
    
    const int K = 19;
    vector dp(K, vector<int>(D, -INF));
    rep(i, D) dp[0][i] = x[i];
    rep(i, K-1) {
        dp[i+1] = dp[i];
        rep(j, D) {
            int nj = j+(1<<i);
            if (nj >= D) break;
            chmax(dp[i+1][j], dp[i][nj]); 
        }
    }
    
    auto f = [&](P p, int w) {
        auto [i, j] = p;
        if (i != -1 and j+w <= x[i]) return P(i, j+w);
        int ni = i+1;
        // while (ni < d and x[ni] < w) ni++;
        for (int k = K-1; k >= 0; --k) {
            if (w > dp[k][ni]) ni += 1<<k;
            if (ni >= D) return P(INF, INF);
        }
        return P(ni, w);
    };
    
    while (q.size()) {
        auto [p, v] = q.top(); q.pop();
        if (dist[v] != p) continue;
        for (auto& e : g[v]) {
            push(e.to, f(p, e.w));
        }
    }
    
    rep(i, n) {
        int ans = dist[i].first;
        if (ans == INF) ans = -1;
        else ans++;
        cout << ans << '\n';
    }
    
    return 0;
}

T7:Approximate Equalization

由于在最终的数组 \(a\) 中任意两数之差的绝对值不超过 \(1\),所以最终的数组 \(a\) 中至多有两种数,不妨记为 \(x\)\(x+1\)
注意到两种操作不会影响到 \(\sum a_i\),所以我们可以求出 \(x\)\(x+1\) 具体的值以及对应的出现次数,即 \(x\)\(x+1\) 分别为 \(\lfloor\frac{\sum a_i}{n}\rfloor\)\(\lfloor\frac{\sum a_i}{n}\rfloor +1\)

dp[i][j] 表示在前 \(i\) 个数中有 \(j\) 个数被变成了 \(x+1\) 的最小操作次数

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

using namespace std;
using ll = long long;

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

int main() {
    int n;
    cin >> n;
    
    vector<ll> a(n);
    rep(i, n) cin >> a[i];
    rep(i, n) a[i] += 1e9;
    
    ll s = reduce(a.begin(), a.end());
    rep(i, n) a[i] -= s/n;
    s %= n;
    rep(i, n-1) a[i+1] += a[i];
    
    const ll INF = 1e18;
    vector<ll> dp(s+1, INF);
    dp[0] = 0;
    rep(i, n) {
        vector<ll> p(s+1, INF); swap(dp, p);
        rep(j, s+1) {
            chmin(dp[j], p[j]);
            if (j+1 <= s) chmin(dp[j+1], p[j]);
        }
        rep(j, s+1) dp[j] += abs(a[i]-j);
    } 
    
    cout << dp[s] << '\n';
    
    return 0;
}