C. K-bonacci
前缀和
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using mint = modint;
int main() {
int n, k;
cin >> n >> k;
vector<mint> a(max(k, n+1));
vector<mint> s(a.size()+1);
rep(i, k) a[i] = 1;
rep(i, k) s[i+1] = s[i]+a[i];
mint::set_mod(1e9);
for (int i = k; i <= n; ++i) {
a[i]= s[i] - s[i-k];
s[i+1] = s[i]+a[i];
}
cout << a[n].val() << '\n';
return 0;
}
还有另一种做法
\(a_n = 2_{n-1} - a_{n-k-1}\)
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using mint = modint;
int main() {
int n, k;
cin >> n >> k;
vector<mint> a(max(k, n+1));
rep(i, k) a[i] = 1;
a[k] = k;
mint::set_mod(1e9);
for (int i = k+1; i <= n; ++i) {
a[i]= 2*a[i-1] - a[i-k-1];
}
cout << a[n].val() << '\n';
return 0;
}
D. Logical Filling
如果 o 旁边有 ?,这个 ? 只能改成 .
然后进行分类讨论!
如果 \(S\) 中 o 的数量等于 \(k\) 时,那么所有的 ? 只能替换为 .
如果不同,则只有在需要将 o 紧密排列时,o 的位置才会确定,因此需要计算最多可以增加多少个 o,如果这个数量恰好等于 \(k\) 时,就在 ? 连续出现奇数个的地方紧密排列 o!
代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, k;
string s;
cin >> n >> k >> s;
rep(i, n) {
if (s[i] == 'o') {
if (i) s[i-1] = '.';
if (i+1 < n) s[i+1] = '.';
}
}
int x = k - ranges::count(s, 'o');
vector<pair<int, int>> ps;
{
int i = 0;
while (i < n) {
if (s[i] == '?') {
int l = i;
while (i < n and s[i] == '?') i++;
int r = i;
ps.emplace_back(l, r);
}
else i++;
}
}
int mx = 0;
for (auto [l, r] : ps) mx += (r-l+1)/2;
if (x == 0) {
for (auto [l, r] : ps) {
for (int i = l; i < r; ++i) s[i] = '.';
}
}
else if (x == mx) {
for (auto [l, r] : ps) {
if ((r-l)%2 == 0) continue;
rep(i, r-l) {
s[l+i] = "o."[i%2];
}
}
}
cout << s << '\n';
return 0;
}
E. Reachable Set
首先,当删除所有大于 \(k\) 的点时,如果无法到达 \(\leqslant k\) 的点,那么答案是 \(-1\)。
如果不是,那么所有直接连接到 \(\leqslant k\) 的点的那些点都必须全部删除,删除后 \(\leqslant k\) 的点和大于 \(k\) 的点将不再连通,这样就满足条件了。
这两个条件可以按照 \(k\) 的顺序分别判断!
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> to(n);
rep(i, m) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
to[b].push_back(a);
}
dsu uf(n);
vector<bool> red(n); int cnt = 0;
rep(v, n) {
for (int u : to[v]) {
if (u < v) uf.merge(u, v);
if (u > v) {
if (red[u]) continue;
red[u] = true;
cnt++;
}
}
if (red[v]) cnt--;
int ans = -1;
if (uf.size(v) == v+1) ans = cnt;
cout << ans << '\n';
}
return 0;
}
F. Add One Edge 3
需要考虑树的直径!
将两树合并后得到的新树的直径要么是经过新添加的边,要么是原来某颗树的直径。
在原树中,每个点到最远点的距离分别记为 \(D1_i\) 和 \(D2_i\),那么 \(f(i, j)\) 就是 \(\max(树1的直径,树2的直径,D1_i + D2_j+1)\)
由于最远点是直径的两端点之一,因此 \(D1_i\) 和 \(D2_i\) 都可以在 \(O(N)\) 时间全部求出来。
计算 \(\sum\sum f(i, j)\) 可以使用类似双指针的方法,或者 \(\operatorname{fft}\) 来实现!
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
using P = pair<int, int>;
int main() {
auto readTree = [&]() {
int n;
cin >> n;
vector<vector<int>> to(n);
rep(i, n-1) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
to[b].push_back(a);
}
vector<int> dist(n);
auto dfs = [&](auto& f, int v, int dep=0, int p=-1) -> P {
dist[v] = max(dist[v], dep);
P res(dep, v);
for (int u : to[v]) {
if (u == p) continue;
res = max(res, f(f, u, dep+1, v));
}
return res;
};
int a = dfs(dfs, 0).second;
auto [d, b] = dfs(dfs, a);
dfs(dfs, b);
vector<ll> c(n);
rep(i, n) c[dist[i]]++;
return make_pair(d, c);
};
auto [da, a] = readTree();
auto [db, b] = readTree();
int d = max(da, db);
auto c = convolution_ll(a, b);
ll ans = 0;
rep(i, c.size()) {
ans += max(i+1, d)*c[i];
}
cout << ans << '\n';
return 0;
}
G. Push Simultaneously
二分答案
考虑“能否在 \(t\) 秒内完成”的判定问题,可以转化为二分图匹配问题!也就是判定二分图最大匹配是否是完美匹配。
代码实现
#include <bits/stdc++.h>
#include <atcoder/all>
using namespace atcoder;
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n;
cin >> n;
vector<pair<ll, ll>> s, t;
rep(i, n) {
ll x, y;
cin >> x >> y;
s.emplace_back(x, y);
}
rep(i, n) {
ll x, y;
cin >> x >> y;
t.emplace_back(x, y);
}
vector dist(n, vector<double>(n));
vector<double> dists;
rep(i, n)rep(j, n) {
auto [sx, sy] = s[i];
auto [tx, ty] = t[j];
dist[i][j] = hypot(sx-tx, sy-ty);
dists.push_back(dist[i][j]);
}
ranges::sort(dists);
auto judge = [&](double x) {
int sv = n*2, tv = sv+1;
mf_graph<int> g(tv+1);
rep(i, n) g.add_edge(sv, i, 1);
rep(i, n) g.add_edge(n+i, tv, 1);
rep(i, n)rep(j, n) if (dist[i][j] <= x) {
g.add_edge(i, n+j, 1);
}
return g.flow(sv, tv) == n;
};
int ac = dists.size()-1, wa = -1;
while (ac-wa > 1) {
int wj = (ac+wa)/2;
(judge(dists[wj]) ? ac : wa) = wj;
}
printf("%.10f\n", dists[ac]);
return 0;
}
浙公网安备 33010602011771号