T1:Echo

模拟

代码实现
n = int(input())
s = input()
ans = ''
for c in s:
ans += c+c
print(ans)

T2:Base 2

C++ 中 long long 最大为 2631unsigned long long 最大为 2641

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ull = unsigned long long;
int main() {
ull ans = 0;
rep(i, 64) {
ull a;
cin >> a;
ans += a<<i;
}
cout << ans << '\n';
return 0;
}

T3:Centers

可以开一个桶来记录每个数的出现次数

在扫描每个数的同时,更新 ai 的出现次数,如果此时这个值为 2,则将 ai 添加到答案末尾

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
int n3 = n*3;
vector<int> a(n3);
rep(i, n3) cin >> a[i];
vector<vector<int>> ps(n+1);
rep(i, n3) ps[a[i]].push_back(i);
vector<int> cnt(n+1);
vector<int> ans;
rep(i, n3) {
cnt[a[i]]++;
if (cnt[a[i]] == 2) ans.push_back(a[i]);
}
rep(i, n) cout << ans[i] << ' ';
return 0;
}

T4:Poisonous Full-Course

必要的信息:

  • 当前是否中毒

dp[i][p] 表示从前 i 道菜中选择若干道菜使得当前的健康状态为 p 时的美味度总和的最大值

最后的答案为 max(dp[n][0],dp[n][1])

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
inline void chmax(ll& x, ll y) { if (x < y) x = y; }
int main() {
int n;
cin >> n;
vector<int> x(n), y(n);
rep(i, n) cin >> x[i] >> y[i];
const ll INF = 1e18;
vector dp(n+1, vector<ll>(2, -INF));
dp[0][0] = 0;
rep(i, n) {
chmax(dp[i+1][0], dp[i][0]);
chmax(dp[i+1][1], dp[i][1]);
if (x[i] == 0) {
chmax(dp[i+1][0], dp[i][0]+y[i]);
chmax(dp[i+1][0], dp[i][1]+y[i]);
}
else {
chmax(dp[i+1][1], dp[i][0]+y[i]);
}
}
ll ans = max(dp[n][0], dp[n][1]);
cout << ans << '\n';
return 0;
}

T5:Best Performances

需要设计一个数据结构满足以下需求:

  • 删除
  • 添加
  • 查询最大的 k 个数的和

可以用两个 std::multiset 来实现,一个用来维护前 k 大的数,另一个用来维护剩下的数

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
using ll = long long;
int main() {
int n, k, q;
cin >> n >> k >> q;
vector<int> a(n);
multiset<int> s, t;
rep(i, k) s.insert(0);
rep(i, n-k) t.insert(0);
ll ans = 0;
auto add = [&](int x) {
s.insert(x); ans += x;
int y = *s.begin();
s.erase(s.find(y)); ans -= y;
t.insert(y);
};
auto del = [&](int x) {
if (s.find(x) != s.end()) {
s.erase(s.find(x)); ans -= x;
int y = *t.rbegin();
t.erase(t.find(y));
s.insert(y); ans += y;
}
else {
t.erase(t.find(x));
}
};
rep(qi, q) {
int x, y;
cin >> x >> y;
--x;
add(y);
del(a[x]);
a[x] = y;
cout << ans << '\n';
}
return 0;
}

T6:Merge Sets

对于 f(S1,S2) 而言,假设 xS1,那么 xf 的贡献就是他在 S1 中按升序排序后的排名,再加上 S2 中小于 x 的数的个数
由于前面一部分的总和为 1+2++m=m(m+1)2 是固定的,所以可以先对 S1 做升序排序,然后用树状数组来统计第二部分的贡献
由于一共要计算 (n2) 项的总和,所以第一部分总的贡献就是 m(m+1)2×(n2)
第二部分总的贡献就是将每个集合排序后拼接起来的序列的逆序数

时间复杂度为 O(nmlog(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;
using P = pair<int, int>;
int main() {
int n, m;
cin >> n >> m;
vector a(n, vector<int>(m));
rep(i, n)rep(j, m) cin >> a[i][j];
vector<P> b;
rep(i, n)rep(j, m) b.emplace_back(a[i][j], i);
sort(b.begin(), b.end());
ll ans = ll((m+1)*m/2) * (n*(n-1)/2);
fenwick_tree<int> t(n);
for (auto [_, x] : b) {
t.add(x, 1);
ans += t.sum(x+1, n);
}
cout << ans << '\n';
return 0;
}

T7:Return to 1

首先将和点 1 不在同一个强连通分量中的点删掉

S 为所有包含点 1 的环的长度的集合,gS 中所有数的最大公约数
当且仅当 g1010100 的因子时,答案是有解的。

S 可能是无限集,这样就找不到 g 了。

现在,任取一个以点 1 为根的 dfs 生成树 T,令 di 为点 iT 上的深度

性质:

  • 对于任意正整数 x 而言,S 中包含一个不是 x 的倍数的数 存在一条有向边 uv,使得 |du+1dv|0(modx)

对于可行解的 g 中只存在素因子 p=2,5
考虑环长是否是 p 的倍数

环的长度为 p 的倍数
对于所有的边 uv,有 d[u]+1d[v](modp)
对于所有的边 uv,有 d[u]+1d[v]0(modp)
对于所有的边 uv,有 p 整除 d[u]+1d[v]
p 整除所有的边 uv 对应的 d[u]+1d[v]gcd

所以,令 gT 上所有非树边对应的 |du+1dv| 的最大公约数,此时 g=g

加强版:

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int>> to(n), ot(n);
rep(i, m) {
int a, b;
cin >> a >> b;
--a; --b;
to[a].push_back(b);
ot[b].push_back(a);
}
vector<bool> ok(n);
{
queue<int> q;
q.push(0); ok[0] = true;
while (q.size()) {
int v = q.front(); q.pop();
for (int u : ot[v]) {
if (ok[u]) continue;
ok[u] = true;
q.push(u);
}
}
}
int g = 0;
vector<int> d(n, -1);
auto dfs = [&](auto f, int v, int nd=0) -> void {
if (d[v] != -1) {
int x = abs(nd-d[v]);
if (x and ok[v]) g = gcd(g, x);
return;
}
d[v] = nd;
for (int u : to[v]) {
f(f, u, nd+1);
}
};
dfs(dfs, 0);
while (g and g%2 == 0) g /= 2;
while (g and g%5 == 0) g /= 5;
if (g == 1) puts("Yes");
else puts("No");
}
int main() {
int t;
cin >> t;
while (t--) solve();
return 0;
}