T1:Echo
模拟
代码实现
n = int(input())
s = input()
ans = ''
for c in s:
ans += c+c
print(ans)
T2:Base 2
C++ 中 long long 最大为 \(2^{63}-1\),unsigned long long 最大为 \(2^{64}-1\)
代码实现
#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
可以开一个桶来记录每个数的出现次数
在扫描每个数的同时,更新 \(a_i\) 的出现次数,如果此时这个值为 \(2\),则将 \(a_i\) 添加到答案末尾
代码实现
#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(S_1, S_2)\) 而言,假设 \(x \in S_1\),那么 \(x\) 对 \(f\) 的贡献就是他在 \(S_1\) 中按升序排序后的排名,再加上 \(S_2\) 中小于 \(x\) 的数的个数
由于前面一部分的总和为 \(1+2+\cdots+m = \frac{m(m+1)}{2}\) 是固定的,所以可以先对 \(S_1\) 做升序排序,然后用树状数组来统计第二部分的贡献
由于一共要计算 \(\binom{n}{2}\) 项的总和,所以第一部分总的贡献就是 \(\frac{m(m+1)}{2} \times \binom{n}{2}\)
第二部分总的贡献就是将每个集合排序后拼接起来的序列的逆序数
时间复杂度为 \(\mathcal{O}(nm\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;
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\) 的环的长度的集合,\(g\) 为 \(S\) 中所有数的最大公约数
当且仅当 \(g\) 为 \(10^{10^{100}}\) 的因子时,答案是有解的。
但 \(S\) 可能是无限集,这样就找不到 \(g\) 了。
现在,任取一个以点 \(1\) 为根的 \(\operatorname{dfs}\) 生成树 \(T\),令 \(d_i\) 为点 \(i\) 在 \(T\) 上的深度
性质:
- 对于任意正整数 \(x\) 而言,\(S\) 中包含一个不是 \(x\) 的倍数的数 \(\Leftrightarrow\) 存在一条有向边 \(u \to v\),使得 \(|d_u+1-d_v| \neq 0 \pmod x\)
对于可行解的 \(g\) 中只存在素因子 \(p = 2, 5\)
考虑环长是否是 \(p\) 的倍数
环的长度为 \(p\) 的倍数
\(\Leftrightarrow\) 对于所有的边 \(u \to v\),有 \(d[u]+1 \equiv d[v] \pmod p\)
\(\Leftrightarrow\) 对于所有的边 \(u \to v\),有 \(d[u]+1 - d[v] \equiv 0 \pmod p\)
\(\Leftrightarrow\) 对于所有的边 \(u \to v\),有 \(p\) 整除 \(d[u]+1-d[v]\)
\(\Leftrightarrow\) \(p\) 整除所有的边 \(u \to v\) 对应的 \(d[u]+1-d[v]\) 的 \(\gcd\)
所以,令 \(g'\) 为 \(T\) 上所有非树边对应的 \(|d_u+1-d_v|\) 的最大公约数,此时 \(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;
}
浙公网安备 33010602011771号