T1:Potions
模拟
代码实现
n, h, x = map(int, input().split())
p = list(map(int, input().split()))
for i in range(n):
if h+p[i] >= x:
exit(print(i+1))
T2:MissingNo.
不妨假设丢失的整数不是其中的最小数,然后用 std::set
来找出那个丢失的数即可
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
set<int> s;
rep(i, n) {
int a;
cin >> a;
s.insert(a);
}
int x = *s.begin();
while (s.count(x)) ++x;
cout << x << '\n';
return 0;
}
T3:Remembering the Days
暴力枚举
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<array<int, 2>>> g(n);
rep(i, m) {
int a, b, c;
cin >> a >> b >> c;
--a; --b;
g[a].push_back({b, c});
g[b].push_back({a, c});
}
int ans = 0;
vector<bool> used(n);
auto f = [&](auto f, int v, int dist) -> void {
used[v] = true;
ans = max(ans, dist);
for (auto [u, w] : g[v]) {
if (used[u]) continue;
f(f, u, dist+w);
}
used[v] = false;
};
rep(i, n) f(f, i, 0);
cout << ans << '\n';
return 0;
}
T4:President
在每个选区,如果通过策反 \(w\) 人就能获得 \(v\) 个议席,那么就变成了背包问题
记 \(d=\) 青木的议席数 -
高桥的议席数
我们只需让 \(d < 0\),那么高桥就赢了
注意到每次让高桥的议席数 +v
,相应的青木的议席数就会 -v
,那么 \(d\) 就会减少 \(2v\)
记 dp[i][j]
表示到第 \(i\) 个选区为止,为了使得 \(\sum v'=j\) 所需要策反的人数的最小值,其中 \(v' = 2v\)
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
inline void chmin(ll& a, ll b) { if (a > b) a = b; }
int main() {
int n;
cin >> n;
int w = 0;
vector<P> data;
rep(i, n) {
int x, y, z;
cin >> x >> y >> z;
int a = max(0, (y-x+1)/2);
w += z;
data.emplace_back(a, z*2);
}
const ll INF = 1e18;
vector dp(n+1, vector<ll>(w+1, INF));
dp[0][0] = 0;
rep(i, n) {
auto [a, z] = data[i];
rep(j, w+1) {
chmin(dp[i+1][j], dp[i][j]);
chmin(dp[i+1][min(w, j+z)], dp[i][j]+a);
}
}
ll ans = dp[n][w];
cout << ans << '\n';
return 0;
}
T5:Avoid Eye Contact
先找到所有进入别人视线无法而通过的格子,然后 \(\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 h, w;
cin >> h >> w;
vector<string> s(h);
rep(i, h) cin >> s[i];
int si, sj, gi, gj;
rep(i, h)rep(j, w) {
if (s[i][j] == 'S') si = i, sj = j, s[i][j] = '.';
if (s[i][j] == 'G') gi = i, gj = j, s[i][j] = '.';
}
vector ng(h, vector<bool>(w));
rep(i, h)rep(j, w) {
int v = -1;
if (s[i][j] == '^') v = 0;
if (s[i][j] == '<') v = 1;
if (s[i][j] == 'v') v = 2;
if (s[i][j] == '>') v = 3;
if (s[i][j] == '#') ng[i][j] = true;
if (v == -1) continue;
int ni = i, nj = j;
while (1) {
ng[ni][nj] = true;
ni += di[v]; nj += dj[v];
if (ni < 0 or nj < 0 or ni >= h or nj >= w) break;
if (s[ni][nj] != '.') break;
}
}
const int INF = 1001001001;
vector dist(h, vector<int>(w, INF));
queue<P> q;
dist[si][sj] = 0; q.emplace(si, sj);
while (q.size()) {
auto [i, j] = q.front(); q.pop();
rep(v, 4) {
int ni = i+di[v], nj = j+dj[v];
if (ni < 0 or nj < 0 or ni >= h or nj >= w) continue;
if (ng[ni][nj]) continue;
if (dist[ni][nj] != INF) continue;
dist[ni][nj] = dist[i][j]+1;
q.emplace(ni, nj);
}
}
int ans = dist[gi][gj];
if (ans == INF) ans = -1;
cout << ans << '\n';
return 0;
}
T6:Nim
数位 \(\operatorname{dp}\)
记 dp[n][f1][f2][f3][r1][r2][r3]
表示满足以下条件的三元组 \((x_1, x_2, x_3)\) 的个数:
- 对于每个 \(i\),\(0 \leqslant x_i < 2^n\)
- \(x_1 \oplus x_2 \oplus x_3 = 0\)
- 对于每个 \(i\),\(x_i\) 是否不超过 \(n\&(2^n-1)\) 的逻辑值为 \(f_i\)
- 对于每个 \(i\),\(x_i\) 对 \(A_i\) 取模的余数为 \(r_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 ll = long long;
using mint = modint998244353;
int main() {
ll n;
cin >> n;
n++;
const int m = 3;
vector<int> a(m);
rep(i, m) cin >> a[i];
vector<int> ds;
while (n) {
ds.emplace_back(n&1);
n >>= 1;
}
reverse(ds.begin(), ds.end());
using T = tuple<int, bool, bool>;
using VT = vector<T>;
map<VT, mint> dp;
dp[VT(3)] = 1;
for (int digit : ds) {
map<VT, mint> pre; swap(dp, pre);
for (auto [s, num] : pre) {
rep(b, 1<<m) {
if (__builtin_parity(b)) continue;
bool ok = true;
VT ns;
rep(i, m) {
auto [md, lt, z] = s[i];
int nb = b>>i&1;
md = (md*2+nb)%a[i];
z |= nb;
if (!lt and nb > digit) ok = false;
lt |= nb < digit;
ns.emplace_back(md, lt, z);
}
if (ok) dp[ns] += num;
}
}
}
mint ans = dp[VT(3, {0, 1, 1})];
cout << ans.val() << '\n';
return 0;
}
T7:Rearranging
这题是行和数字匹配的二分图匹配问题,跑 \(m\) 次二分图匹配就能解决问题!
代码实现
#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;
int main() {
int n, m;
cin >> n >> m;
vector a(n, vector<int>(m));
rep(i, n)rep(j, m) cin >> a[i][j], a[i][j]--;
int sv = n+n, tv = sv+1;
mf_graph<int> g(tv+1);
rep(i, n)rep(j, m) g.add_edge(i, n+a[i][j], 1);
rep(i, n) g.add_edge(sv, i, 1);
rep(i, n) g.add_edge(n+i, tv, 1);
vector<vector<int>> ans(n);
rep(mi, m) {
assert(g.flow(sv, tv) == n);
rep(i, n)rep(j, m) {
int ei = i*m+j;
if (g.get_edge(ei).flow) {
ans[i].push_back(a[i][j]+1);
g.change_edge(ei, 0, 0);
}
}
rep(i, n+n) g.change_edge(n*m+i, 1, 0);
}
puts("Yes");
rep(i, n) {
rep(j, m) cout << ans[i][j] << " \n"[j == m-1];
}
return 0;
}