2024 天梯选拔赛(二)
2024 天梯选拔赛(二)
L1-1.□□,□□!
print("yuan shen, qi dong!")
L1-2.比较大小
\(log_22^x = x, \frac{1}{\sqrt x^2} = \frac{1}{x}\),两者比较一下即可
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
double x;
cin >> x;
if(x < 1) cout << '<';
else if(x > 1) cout << '>';
else cout << '=';
return 0;
}
L1-3.基于金铲铲的期望学习
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
double ans = 0;
if (n <= 8) ans = 2 * n;
else ans = n + 8;
printf("%.2lf",ans/n);
return 0;
}
L1-4.奇怪的克制倍数
按题意模拟即可
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
double ai, aj, bi, bj;
cin >> ai >> aj >> bi >> bj;
double a = 0, b = 0;
auto df = [](double y, double z) {
double x = 0 ;
x = (y + z) / 2;
if (!y || !z) x /= 2;
if (y == 2 && z == 2)
x *= 2;
return x;
};
a = df(ai, aj), b = df(bi, bj);
printf("%.6lf\n", (a + b) / 2);
return 0;
}
L1-5.红石难题
把所有红石相连处理出一条直线,对于一个红石信号源,其可以使覆盖边界最小为\(m\)的范围为\(D = (15-m)\times 2 + 1\),即两边加中间,所以答案为\(\lceil \frac{sum}{D} \rceil\),特别的,当\(m\)为\(0\)时,输出\(0\);
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<i64> x(n), y(n);
i64 sum = 1;
for (int i = 0; i < n; i ++) {
cin >> x[i] >> y[i];
if (i) sum += abs(x[i] - x[i - 1]) + abs(y[i] - y[i - 1]);
}
if(!m){
cout << 0 << '\n';
return 0;
}
int d = (15 - m) * 2 + 1;
cout << (sum + d - 1) / d << '\n';
return 0;
}
L1-6.基于文化课的算法学习
记录字符串"main"和"return"数量,两者数量相等时则为代码外,若最后两者不相等或者都没出现过,则为代码有误;
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
string s, str;
cin >> n >> s >> str;
int ma = 0, re = 0;
for (int i = 0; i < str.size(); i ++) {
string t = str.substr(i, s.size());
if (str.substr(i, 4) == "main") ma ++;
if (str.substr(i, 6) == "return") re ++;
if (t == s && ma == re) {
str[i] = 'z';
str[i + 1] = 'x';
str[i + 2] = 'z';
}
}
if (ma != re || (!ma && !re)) {
cout << "wrong\n";
} else {
cout << str << '\n';
}
return 0;
}
L1-7.奶茶袋收集
处理出差分数组,可以发现要使得极差最小就是在最大的差值处插入一块板子,将差值大的两者分开,不让它们在同一组;
对差分数组排序,去掉\((m-1)\)个最大的差值即可;
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n,m;
cin >> n >> m;
vector<int> a(n);
for(auto &i : a) cin >> i;
vector<int> res;
for(int i = 1;i < n;i ++){
res.push_back(a[i] - a[i - 1]);
}
sort(res.begin(),res.end());
i64 ans = 0;
for(int i = 0;i < res.size() - m + 1;i ++)
ans += res[i];
cout << ans << '\n';
return 0;
}
L1-8.该加训啦
运用真值表可知\((a\&b)\oplus (a|b) = (a\oplus b)\),即\(f(a,b)=(a\oplus b)\);
根据异或的性质,我们可以求出异或前缀和,通过做差求出区间异或值;
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<int> a(n + 1), pre(n + 1);
for (int i = 1; i <= n; i ++) {
cin >> a[i];
pre[i] = (pre[i - 1] ^ a[i]);
}
int m;
cin >> m;
while (m --) {
int l, r;
cin >> l >> r;
cout << (pre[r] ^ pre[l-1]) << '\n';
}
return 0;
}
L2-1.cy的倒金字塔工厂
按题意运用\(STL\)模拟即可
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, k;
cin >> n >> k;
vector<int> line(n);
for (auto &i : line) cin >> i;
stack<int> box, Ta;
vector<vector<int>> ans;
vector<int> waste;
while (box.size() || line.size()) {
if (line.size()) {
int x = line.back();
line.pop_back();
if (!Ta.size()) {
Ta.push(x);
} else {
int y = Ta.top();
if (x > y && x - y <= k) {
Ta.push(x);
} else {
if (box.size()) {
int z = box.top();
if (z > y && z - y <= k) {
Ta.push(z);
box.pop();
}
}
box.push(x);
}
}
} else {
if (Ta.size() >= 2) {
vector<int> Pin;
while (Ta.size()) {
Pin.push_back(Ta.top());
Ta.pop();
}
ans.push_back(Pin);
} else if (Ta.size() == 1) {
waste.push_back(Ta.top());
Ta.pop();
}
if (box.size()) {
while (box.size()) {
line.push_back(box.top());
box.pop();
}
reverse(line.begin(), line.end());
}
}
}
if (Ta.size() >= 2) {
vector<int> Pin;
while (Ta.size()) {
Pin.push_back(Ta.top());
Ta.pop();
}
ans.push_back(Pin);
} else if (Ta.size() == 1) {
waste.push_back(Ta.top());
Ta.pop();
}
for (auto ve : ans) {
for (auto v : ve)
cout << v << ' ';
cout << '\n';
}
if (waste.size()) {
for (auto i : waste)
cout << i << ' ';
cout << '\n';
}
return 0;
}
L2-2.swj学长的精灵融合
按题意模拟出融合的关系可以发现其实就是一颗树,且要求我们从叶子节点往根节点递推;
推出精灵的各等级所需经验后,用\(dfs\)跑一遍树即可;
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
struct Node {
int b, c, d;
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<vector<i64>> jy(4, vector<i64>(110, 1));
jy[1][1] = jy[2][1] = jy[3][1] = 0;
for (int i = 3; i <= 100; i ++) {
jy[1][i] = jy[1][i - 1] + (i - 2);
jy[2][i] = jy[2][i - 1] + (i - 2) * 2;
jy[3][i] = jy[3][i - 1] + (i - 2) * 5;
}
map<int, vector<Node>> mp;
for (int i = 0; i < m; i ++) {
int a, b, c, d;
cin >> a >> b >> c >> d;
mp[a].push_back({b, c, d});
}
i64 ans = 0;
auto dfs = [&](auto self, int x) -> void{
for (auto [v, c, d] : mp[x]) {
self(self, v);
ans += jy[c][d];
}
};
dfs(dfs, n);
cout << ans << '\n';
return 0;
}
L2-3.幸运号码
先处理出各字符串的数字和\(sum\),然后把它们的和与其奇偶性关联起来,即用一个二维数组\(cnt[sum[i]][j]\)存储;
对于两个字符串\(S_i,S_j\),如果它们符合要求,即存在一个位置\(pos\)使得\(LeftSum_{pos} = RightSum_{pos}\),如果\(pos\)在\(S_i\)中,即可得到\(lsum = (sum[i] - rsum) + sum[j]\),如果\(pos\)在\(S_j\)中,那我们只要反着再求一遍即可;
特别的,第一次求的时候如果你计算到了\(S_i\)的边界,那么在反转后求得时候就不能再求\(S_i[0]\),这样会重复计算;
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin >> n;
vector<string> s(n);
vector cnt(111, vector<int>(2));
vector<i64> sum(n);
auto get = [](string str) {
int res = 0;
for (auto i : str)
res += (i - '0');
return res;
};
for (int i = 0; i < n; i ++) {
cin >> s[i];
sum[i] = get(s[i]);
cnt[sum[i]][s[i].size() & 1] ++;
}
auto solve = [&](vector<string>& s,int f) {
i64 res = 0;
for (int i = 0; i < n; i ++) {
int lsum = 0;
for (auto j : s[i]) {
lsum += (j - '0');
int rsum = sum[i] - lsum;
if (rsum > lsum) continue;
res += cnt[lsum - rsum][(s[i].size() + f) & 1];
}
}
return res;
};
i64 ans = 0;
ans += solve(s,0);
for (auto &i : s)
reverse(i.begin(), i.end()),i.pop_back();
ans += solve(s,1);
cout << ans << '\n';
return 0;
}
L2-4.恶心的广告
传统的\(BFS\)无法判断在当前位置上还能够打败哪些敌人,所以应该引入\(priority\_queue\)即优先队列来跑\(BFS\);
将敌人的数值作为关键字排序,保证每次\(BFS\)都能够在可走范围内打数值最低的敌人,当最低数值也打不过时则可以退出了;
特别的,对于药剂,我们可以直接获取其数值,然后把它当做数值为\(0\)的敌人再放入队列中;
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, x, y, t;
cin >> n >> m >> x >> y >> t;
vector mp(n + 1, vector<int>(m + 1));
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
cin >> mp[i][j];
set<PII> JI;
for (int i = 0; i < t; i ++) {
int x, y;
cin >> x >> y;
JI.insert({x, y});
}
vector vis(n + 1, vector<bool>(m + 1));
using PIII = pair<int, PII>;
priority_queue<PIII, vector<PIII>, greater<PIII>> Q;
int u[] = {1, -1, 0, 0}, v[] = {0, 0, 1, -1};
i64 ans = 0;
ans += mp[x][y];
mp[x][y] = 0, vis[x][y] = 1;
Q.push({0, {x, y}});
while (Q.size()) {
auto [w, loc] = Q.top();
auto [xi, yi] = loc;
Q.pop();
if (w > ans) {
break;
}
ans += w;
for (int i = 0; i < 4; i ++) {
int dx = xi + u[i];
int dy = yi + v[i];
if (dx >= 1 && dx <= n && dy >= 1 && dy <= m && !vis[dx][dy]) {
if (JI.count({dx, dy})) {
ans += mp[dx][dy];
mp[dx][dy] = 0;
Q.push({0, {dx, dy}});
vis[dx][dy] = 1;
} else {
Q.push({mp[dx][dy], {dx, dy}});
vis[dx][dy] = 1;
}
}
}
}
cout << ans << '\n';
return 0;
}
L3-1.Drmeng与商品
设\(dp[i][j]\)为前\(i\)个商品中能选出\(j\)组;
按题意即就是一个线性\(dp\),需要我们用前缀和去处理\(i\)到\(i-m\)的商品价值;
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m, k;
cin >> n >> m >> k;
vector dp(n + 1, vector<i64>(k + 1, -1));
vector<i64> p(n + 1), sum(n + 1);
dp[0][0] = 0;
for (int i = 1; i <= n; i ++) {
cin >> p[i];
sum[i] = sum[i - 1] + p[i];
dp[i][0] = 0;
}
for (int i = m; i <= n; i ++) {
for (int j = 1; j <= k; j ++) {
dp[i][j] = dp[i - 1][j];
if (dp[i - m][j - 1] != -1)
dp[i][j] = max(dp[i][j], dp[i - m][j - 1] + sum[i] - sum[i - m]);
}
}
cout << dp[n][k] << '\n';
vector<PII> ans;
int cnt = 1;
while (k) {
if (dp[n][k] == dp[n - m][k - 1] + sum[n] - sum[n - m]) {
ans.emplace_back(n - m + 1, n);
k --;
n -= m;
} else n --;
}
for (auto [x, y] : ans)
cout << x << ' ' << y << '\n';
return 0;
}
L3-2.黄金树影
读懂题意后就是要求我们求出这棵树的\(dfs\)序,然后用线段树或树状数组查询和修改即可;
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<'\n';
using namespace std;
using i64 = long long;
typedef pair<i64, i64> PII;
template<typename T>
struct BIT {
#ifndef lowbit
#define lowbit(x) (x & (-x));
#endif
int n;
vector<T> t;
BIT () {}
BIT (int _n): n(_n) { t.resize(_n + 1); }
BIT (int _n, vector<T>& a, vector<T>& w): n(_n) {
vector<T>(n + 1).swap(t);
for (int i = 1; i <= n; ++ i) {
t[i] += w[a[i]];
int j = i + lowbit(i);
if (j <= n) t[j] += t[i];
}
}
//单点修改
void update(int i, T x) {
while (i <= n) {
t[i] += x;
i += lowbit(i);
}
}
//区间查询
T sum(int i) {
T ans = 0;
while (i > 0) {
ans += t[i];
i -= lowbit(i);
}
return ans;
}
T query(int i, int j) {
return sum(j) - sum(i - 1);
}
//区间修改则存入差分数组,[l, r] + k则update(x,k),update(y+1,-k)
//单点查询则直接求前缀和sum(x)
};
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
vector<i64> w(n + 1);
for (int i = 1; i <= n; i ++)
cin >> w[i];
vector g(n + 1, vector<int>());
for (int i = 2; i <= n; i ++) {
int u;
cin >> u;
g[i].push_back(u);
g[u].push_back(i);
}
vector<i64> st(n + 1), ed(n + 1), Xu{0};
auto dfs = [&](auto self, int u, int fa)->void{
st[u] = Xu.size();
Xu.push_back(u);
for (auto v : g[u]) {
if (v == fa) continue;
self(self, v, u);
}
ed[u] = Xu.size();
Xu.push_back(u);
};
dfs(dfs, 1, 0);
BIT<i64> tree(Xu.size(), Xu, w);
while (m --) {
i64 op, a, x;
cin >> op >> a;
if (op == 1) {
cin >> x;
tree.update(st[a], x);
tree.update(ed[a], x);
} else {
cout << tree.query(st[a], ed[a]) / 2 << '\n';
}
}
return 0;
}