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\) 所在的连通分量中的点的位置
注意原图可能有环,所以不能跑拓扑排序
这里我们可以用 \(\operatorname{dfs}\)\(\operatorname{bfs}\) 解决
注意需要存无向边,因为从点 \(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\) 走到坐标 \(X_i\) 时还剩 \(j\) 升油并且从坐标 \(X_N\) 回到坐标 \(x_i\) 时还剩 \(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(N^2)\) 个点,边数也是 \(O(N^2)\),所以每次跑最大匹配的复杂度是 \(O(N^3)\)。时间复杂度就是 \(O(10N^3\log(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;
}