C. Chokutter Addiction

维护上一次打开的时刻

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

using namespace std;

int main() {
    int n, t;
    cin >> n >> t;
    
    vector<int> a(n);
    rep(i, n) cin >> a[i];
    a.push_back(t);
    
    int open_time = 0;
    
    int ans = 0;
    for (int na : a) {
        if (open_time < na) {
            ans += na-open_time;
            open_time = na+100;
        }
    }
    
    cout << ans << '\n';
    
    return 0;
}

D. Pawn Line

\(T_i\) 为第 \(i\) 列的棋子最终放置的行数

\(T_i\) 只需取 \(\min(R_j + |i-j|)\) 即可

可以先令 \(T \gets R\),,然后做两次扫描来强制相邻差约束:

  • 从左到右:对于 \(i=1, \cdots , n-1\),强制 \(T_{i+1} \leqslant T_i+1\)
  • 从右到左:对于 \(i=n-1, \cdots , 1\),强制 \(T_{i-1} \leqslant T_i+1\)

据说这个好像很典

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

using namespace std;
using ll = long long;

void solve() {
    int n;
    cin >> n;
    
    vector<int> r(n);
    rep(i, n) cin >> r[i];
    
    vector<int> t = r;
    rep(i, n-1) t[i+1] = min(t[i+1], t[i]+1);
    for (int i = n-1; i > 0; --i) {
        t[i-1] = min(t[i-1], t[i]+1);
    }
    
    ll ans = 0;
    rep(i, n) ans += r[i]-t[i];
    
    cout << ans << '\n';
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}

E. Climbing Silver

dp[i][j] 表示格子 \((i, j)\) 是否可达
由于有第二个操作,所以还需维护每一列的底部数组 \(\text{bottom}[j]\),也就是第 \(j\) 列中最底部的墙壁对应的行数

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

using namespace std;

void solve() {
    int n, c;
    cin >> n >> c;
    
    vector<string> s(n);
    rep(i, n) cin >> s[i];
    rep(i, n) s[i] = '#'+s[i]+'#';
    int w = n+2;
    
    vector dp(n, vector<bool>(w));
    dp[n-1][c] = true;
    
    vector<int> bottom(w, n);
    rep(i, n)rep(j, w) if (s[i][j] == '#') bottom[j] = i;
    
    for (int i = n-2; i >= 0; --i) {
        for (int j = 1; j <= n; ++j) {
            if (!dp[i+1][j-1] and !dp[i+1][j] and !dp[i+1][j+1]) continue;
            if (s[i][j] == '#') {
                if (bottom[j] != i) continue;
                rep(ni, n) s[ni][j] = '.';
            }
            dp[i][j] = true;
        }
    }
    
    string ans;
    for (int j = 1; j <= n; ++j) ans += '0'+dp[0][j];
    
    cout << ans << '\n';
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}

F. Non-Increasing Number

dp[x][d] 表示当前数 \(\bmod n\)\(x\) 且个位数为 \(d\) 所对应的前一个状态
然后跑 \(\text{BFS}\)

代码实现
#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> dp(n*10, -1);
    queue<int> q;
    auto push = [&](int x, int d, int ps) {
        x %= n;
        int s = x*10+d;
        if (dp[s] != -1) return;
        dp[s] = ps;
        q.push(s);
    };
    for (int d = 1; d <= 9; ++d) push(d, d, 0);
    while (q.size()) {
        int s = q.front(); q.pop();
        int x = s/10, d = s%10;
        if (x == 0) {
            string ans;
            while (d) {
                ans += '0'+d;
                s = dp[s];
                d = s%10;
            }
            reverse(ans.begin(), ans.end());
            cout << ans << '\n';
            return 0;
        }
        while (d < 10) {
            push(x*10+d, d, s);
            d++;
        }
    }
    
    cout << -1 << '\n';
    
    return 0;
}

G. Another Mod of Linear Problem

\(y_k = A k + B\)
\(y_k\) 写成带余除法的形式,\(y_k = q_k M + r_k\)\(0 ≤ r_k < M\),其中 \(r_k = (A k + B) \bmod M\)
我们要求的就是满足 \(r_k > k\)\(k\) 的个数,也就是求

\[ans = \sum\limits_{k=0}^{N-1} [ r_k ≥ k+1 ] \]

现在考虑表达式
\(S_k := \left\lfloor\frac{(A-1)k + (B-1) + M}{M}\right\rfloor - \left\lfloor\frac{A k + B}{M}\right\rfloor\)

\(q_k\)\(r_k\) 表示第一项:
\((A-1)k + (B-1) + M = A k + B + (M - k - 1)\)

因此

\[\begin{aligned} &\left\lfloor\frac{(A-1)k + (B-1) + M}{M}\right\rfloor\\ =& \left\lfloor\frac{q_k M + r_k + (M - k - 1)}{M}\right\rfloor\\ =& q_k + \left\lfloor\frac{r_k + (M - k - 1)}{M}\right\rfloor\\ \end{aligned} \]

由于 \(0 ≤ k ≤ N-1\)\(N ≤ M\),有 \(M - k - 1 ≥ 0\),所以 \(r_k + (M - k - 1) ≥ M\) 当且仅当 \(r_k ≥ k+1\)。因此
\(\left\lfloor\frac{r_k + (M - k - 1)}{M}\right\rfloor = 1\)\(r_k ≥ k+1\),否则为 \(0\)
于是,\(S_k = q_k + [r_k ≥ k+1] - q_k = [r_k ≥ k+1]\)

所以,对所有 \(k\) 求和有

\[ans = \sum_{k=0}^{N-1} S_k = \sum_{k=0}^{N-1} \left\lfloor\frac{(A-1)k + (B-1) + M}{M}\right\rfloor - \sum_{k=0}^{N-1} \left\lfloor\frac{A k + B}{M}\right\rfloor \]

代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;

using namespace std;
using ll = long long;

void solve() {
    ll n, m, a, b;
    cin >> n >> m >> a >> b;
    
    ll ans = floor_sum(n, m, a-1, b-1+m) - floor_sum(n, m, a, b);
    cout << ans << '\n';
}

int main() {
    int t;
    cin >> t;
    
    while (t--) solve();
    
    return 0;
}