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\) 的个数,也就是求
现在考虑表达式
\(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)\)
因此
由于 \(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\) 求和有
代码实现
#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;
}
浙公网安备 33010602011771号