T1:Leyland Number

模拟

代码实现
a, b = map(int, input().split())
print(a**b+b**a)

T2:Longest Palindrome

模拟

代码实现
#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() {
string s;
cin >> s;
int n = s.size();
int ans = 0;
rep(r, n)rep(l, r+1) {
string ns = s.substr(l, r-l+1);
if (isPalindrome(ns)) ans = max(ans, r-l+1);
}
cout << ans << '\n';
return 0;
}

T3:Slot Strategy 2 (Easy)

暴搜这 3 个转盘停止旋转的时间

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int m;
cin >> m;
vector<string> s(3);
rep(i, 3) cin >> s[i];
const int INF = 1001001001;
int ans = INF;
rep(t0, 300)rep(t1, 300)rep(t2, 300) {
if (t0 == t1) continue;
if (t0 == t2) continue;
if (t1 == t2) continue;
if (s[0][t0%m] != s[1][t1%m]) continue;
if (s[0][t0%m] != s[2][t2%m]) continue;
ans = min(ans, max({t0, t1, t2}));
}
if (ans == INF) ans = -1;
cout << ans << '\n';
return 0;
}

或者暴搜这 3 个转盘停止旋转的顺序以及以哪个数停止

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int m;
cin >> m;
vector<string> s(3);
rep(i, 3) cin >> s[i];
const int INF = 1001001001;
int ans = INF;
vector<int> p = {0, 1, 2};
rep(d, 10) {
char c = '0'+d;
do {
int t = -1;
rep(i, 3) {
t++;
while (t < 300 and s[p[i]][t%m] != c) t++;
}
if (t < 300) ans = min(ans, t);
} while (next_permutation(p.begin(), p.end()));
}
if (ans == INF) ans = -1;
cout << ans << '\n';
return 0;
}

T4:Relative Position

显然我们只需得知点 1 所在的连通分量中的点的位置
注意原图可能有环,所以不能跑拓扑排序
这里我们可以用 dfsbfs 解决
注意需要存无向边,因为从点 1 出发不一定能走到属于同一个连通分量中的某个点

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
struct Edge {
int to, x, y;
Edge(int to=-1, int x=0, int y=0): to(to), x(x), y(y) {}
};
int main() {
int n, m;
cin >> n >> m;
vector<vector<Edge>> g(n);
rep(i, m) {
int a, b, x, y;
cin >> a >> b >> x >> y;
--a; --b;
g[a].emplace_back(b, x, y);
g[b].emplace_back(a, -x, -y);
}
const ll INF = 1e18;
vector<ll> x(n, INF), y(n, INF);
x[0] = y[0] = 0;
queue<int> q;
q.push(0);
while (q.size()) {
int v = q.front(); q.pop();
for (auto [u, dx, dy] : g[v]) {
if (x[u] != INF) continue;
x[u] = x[v]+dx;
y[u] = y[v]+dy;
q.push(u);
}
}
rep(i, n) {
if (x[i] == INF) puts("undecidable");
else cout << x[i] << ' ' << y[i] << '\n';
}
return 0;
}

T5:Somen Nagashi

用小根堆来模拟即可

具体地,开两个小根堆,一个用来维护人的排队顺序,另一个用来维护经过 s 秒后返回这个事件的 (时刻,人)

代码实现
#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>;
template<class T>
using PQ = priority_queue<T, vector<T>, greater<T>>;
int main() {
int n, m;
cin >> n >> m;
PQ<int> q;
rep(i, n) q.push(i);
PQ<P> events;
vector<ll> ans(n);
rep(mi, m) {
int t, w, s;
cin >> t >> w >> s;
while (events.size() and events.top().first <= t) {
q.push(events.top().second); events.pop();
}
if (!q.size()) continue;
int i = q.top(); q.pop();
ans[i] += w;
events.emplace(t+s, i);
}
rep(i, n) cout << ans[i] << '\n';
return 0;
}

T6:Fuel Round Trip

需要同时考虑去和回这两个方向!
dp[i][j][k] 表示从坐标 0 走到坐标 Xi 时还剩 j 升油并且从坐标 XN 回到坐标 xi 时还剩 k 升油的最小费用

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
inline void chmin(int& a, int b) { if (a > b) a = b; }
int main() {
int n, h;
cin >> n >> h;
vector<int> x(n+1);
rep(i, n) cin >> x[i+1];
vector<int> p(n), f(n);
rep(i, n-1) cin >> p[i] >> f[i];
const int INF = 1001001001;
vector dp(h+1, vector<int>(h+1, INF));
rep(i, h+1) dp[h][i] = 0;
rep(i, n) {
vector pre(h+1, vector<int>(h+1, INF));
swap(dp, pre);
int dx = x[i+1]-x[i];
rep(j, h+1)rep(k, h+1) {
int nj = j-dx, nk = k+dx;
if (nj < 0) continue;
if (nk > h) continue;
chmin(dp[nj][nk], pre[j][k]);
chmin(dp[min(h, nj+f[i])][nk], pre[j][k]+p[i]);
if (nk-f[i] >= 0) {
chmin(dp[nj][nk-f[i]], pre[j][k]+p[i]);
}
if (nk == h) {
rep(l, f[i]) chmin(dp[nj][nk-l], pre[j][k]+p[i]);
}
}
}
int ans = INF;
rep(i, h+1) chmin(ans, dp[i][i]);
if (ans == INF) ans = -1;
cout << ans << '\n';
return 0;
}

T7:Slot Strategy 2 (Hard)

一旦确定了目标数字,就变成了时间和卷轴的二分图匹配问题,只需在二分的同时,用网络流判定即可!
但注意到显然每个串里面每个数字只有前 N 次出现有用,所以只需要保留 O(N2) 个点,边数也是 O(N2),所以每次跑最大匹配的复杂度是 O(N3)。时间复杂度就是 O(10N3log(NM))

代码实现
#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;
// Coodinate Compression
template<typename T=int>
struct CC {
bool initialized;
vector<T> xs;
CC(): initialized(false) {}
void add(T x) { xs.push_back(x);}
void init() {
sort(xs.begin(), xs.end());
xs.erase(unique(xs.begin(),xs.end()),xs.end());
initialized = true;
}
int operator()(T x) {
if (!initialized) init();
return upper_bound(xs.begin(), xs.end(), x) - xs.begin() - 1;
}
T operator[](int i) {
if (!initialized) init();
return xs[i];
}
int size() {
if (!initialized) init();
return xs.size();
}
};
int main() {
int n, m;
cin >> n >> m;
vector<string> s(n);
rep(i, n) cin >> s[i];
vector is(10, vector<vector<int>>(n));
vector num(10, vector<int>(n));
rep(i, n)rep(j, m) is[s[i][j]-'0'][i].push_back(j);
rep(d, 10)rep(i, n) num[d][i] = is[d][i].size();
const int INF = 1001001001;
int ans = INF;
rep(d, 10) {
bool ok = true;
rep(i, n) if (num[d][i] == 0) ok = false;
if (!ok) continue;
vector<vector<int>> nis(n);
rep(i, n)rep(j, n) {
int a = j/num[d][i];
int b = j%num[d][i];
nis[i].push_back(is[d][i][b]+a*m);
}
CC cc;
rep(i, n)rep(j, n) cc.add(nis[i][j]);
int w = cc.size();
auto f = [&](int t) {
int sv = n+w, tv = sv+1;
mf_graph<int> g(tv+1);
rep(i, n) g.add_edge(sv, i, 1);
rep(i, w) g.add_edge(n+i, tv, 1);
rep(i, n)rep(j, n) {
if (nis[i][j] <= t) g.add_edge(i, n+cc(nis[i][j]), 1);
}
return g.flow(sv, tv) == n;
};
int ac = n*m, wa = -1;
while (ac-wa > 1) {
int wj = (ac+wa)/2;
if (f(wj)) ac = wj; else wa = wj;
}
ans = min(ans, ac);
}
if (ans == INF) ans = -1;
cout << ans << '\n';
return 0;
}