|–>传送门<–|

A. King of String Comparison 双指针

给定字符串AAA和BBB,计算满足Asub[l,r]A_{sub[l, r]}Asub[l,r]​字典序小于Bsub[l,r]B_{sub[l,r]}Bsub[l,r]​的[l,r][l, r][l,r]的个数。

直接双指针扫一下,扫到满足的前缀就直接进行计数。否则直接跳下一个。

#include <bits/stdc++.h>
#define int long long
using namespace std;inline void solve(){int n = 0; std::cin >> n;std::string a, b; std::cin >> a >> b;int ans = 0;for(int l = 0, r = 0; r < n;){if(l > r) r = l;if(a[r] == b[r]) r++;else if(a[r] < b[r]) ans += (n - r), l++;else l = (r += 1);}std::cout << ans << std::endl;
}signed main(){solve();return 0;
}

B. New Queries On Segment Deluxe 可持久化线段树

牛逼

建2k2^k2k棵可持久化线段树,将区间覆盖操作视为节点接入空树再区间加的操作。思路比较简单,实现有点难。

#include <bits/stdc++.h>
#define int long long
using namespace std;const int N = 21420000;
const int INF = 0x3f3f3f3f;
int a[250005][4], row = 0;//;#define lson lc[rt], l, mid
#define rson rc[rt], mid + 1, r
#define endl '\n'int lc[N], rc[N], root[20005][16], val[N], lazy[N], tot;int create(int rt){int now = ++tot;lc[now] = lc[rt], rc[now] = rc[rt];val[now] = val[rt], lazy[now] = lazy[rt];return now;
}inline void push_up(int rt){ val[rt] = std::min(val[lc[rt]], val[rc[rt]]) + lazy[rt]; }void build(int &rt, int l, int r, int bitt){rt = ++tot;if(l == r){for(int i = 0; i < row; i++) if(bitt >> i & 1) val[rt] += a[l][i];return;}int mid = l + r >> 1;build(lson, bitt), build(rson, bitt);push_up(rt);
}int s = 0, t = 0, d = 0;void update1(int &rt, int l, int r, int u){rt = create(u); //cout << rt << endl;if(s <= l && r <= t){val[rt] += d, lazy[rt] += d;return;}int mid = l + r >> 1;if(s <= mid) update1(lson, lc[u]);if(t > mid) update1(rson, rc[u]);push_up(rt);
}void update2(int &rt, int l, int r, int u, int v, int tmp = 0){if(s <= l && r <= t){rt = create(v); // cout << "DEBUG U21" << rt << endl;val[rt] += d - tmp, lazy[rt] += d - tmp;return;}tmp += lazy[u] - lazy[v];rt = create(u);  //cout << "DEBUG U22" << rt << endl;int mid = l + r >> 1;if(mid >= s) update2(lson, lc[u], lc[v], tmp);if(mid < t) update2(rson, rc[u], rc[v], tmp);push_up(rt);
}int query(int rt, int l, int r){if(l >= s && r <= t) return val[rt];int mid = l + r >> 1, ans = INF; //cout << ans << endl;if(mid >= s) ans = std::min(ans, query(lson));if(mid < t) ans = std::min(ans, query(rson));return ans + lazy[rt];
}void solve(){int n, m; cin >> row >> n >> m;for (int k = 0; k < row; k++)for (int i = 1; i <= n; i++) cin >> a[i][k];//cout << "TAG" << endl;for (int bitt = 0; bitt < (1 << row); bitt++) build(root[0][bitt], 1, n, bitt);for (int i = 1; i <= m; i++){int op, v; cin >> op >> v;if (op == 1){int k; cin >> k >> s >> t >> d, k--;for (int bitt = 0; bitt < (1 << row); bitt++){if (bitt >> k & 1) update1(root[i][bitt], 1, n, root[v][bitt]);else root[i][bitt] = root[v][bitt];}}else if (op == 2){int k; cin >> k >> s >> t >> d, k--;for (int bitt = 0; bitt < (1 << row); bitt++){if (bitt >> k & 1) update2(root[i][bitt], 1, n, root[v][bitt], root[v][bitt ^ (1 << k)]);else root[i][bitt] = root[v][bitt];}}else if (op == 3){cin >> s >> t;cout << query(root[v][(1 << row) - 1], 1, n) << endl;}}
}signed main(){ios_base::sync_with_stdio(false);//cout << N << endl;solve();return 0;
}

C. Werewolves 树形背包

待补

F. to Pay Respects 模拟

你正在进行一场nnn轮的游戏,在游戏中,BOSSBOSSBOSS不会攻击你,但是会吟唱咒语。

在每轮游戏中,事件会按照以下顺序发生。

  1. BOSSBOSSBOSS可以选择吟唱Regeneration咒语
  2. 你可以选择吟唱Poison咒语
  3. 你可以用剑进行攻击,并造成XXX点伤害
  4. 所有负面效果生效

BOSSBOSSBOSS有三个属性,血条hphphp、Poison效果叠加ppp,Regeneration效果叠加rrr。

每层Poison效果可以产生PPP伤害,如果有Regeneration效果就减去一层。每层Regeneration效果可以产生RRR回复。

现在你可以吟唱KKK次法术,问对BOSSBOSSBOSS造成的最大伤害。

思路.1 O(nlogn)O(nlogn)O(nlogn)做法

PoisonRegeneration产生的削弱效果视为攻击产生的效果,记录在每个点施加Poison产生的攻击的效果。然后直接排序取前KKK大攻击效果累加进答案即可。复杂度来自排序O(nlogn)O(nlogn)O(nlogn)。

#include <bits/stdc++.h>
#define int long long
using namespace std;vector<int> atk;inline void solve(){int n, x, r, p, k; cin >> n >> x >> r >> p >> k;string s; cin >> s; s = '@' + s;int ans = x * n;for(int i = 1; i <= n; i++){if(s[i] == '1'){atk.emplace_back((n - i + 1) * (p + r));ans -= (n - i + 1) * r;}else{atk.emplace_back((n - i + 1) * p);}}sort(atk.begin(), atk.end(), [](const int &a, const int &b) { return a > b; });for(int i = 0; i < k; i++) ans += atk[i];cout << ans << endl;}signed main(){solve();return 0;
}

思路.2 O(n)O(n)O(n)做法

来自神犇队友。

首先将前kkk个怪兽回血的点设为放技能的点。如果不足kkk次技能就从头开始补技能。

那么可以用一个双指针,然后将后面的技能往前移动,同时更新贡献取最大值。

由于不需要排序,双指针扫O(n)O(n)O(n)。

太妙了

#include <bits/stdc++.h>
using namespace std;const int N = 1e6 + 10;bitset<N> vis;inline void solve(){int n, x, r, p, k; cin >> n >> x >> r >> p >> k;string s; cin >> s; s = '@' + s;int res = n * x, cnt = 0, ans = -1;for(int i = 1; i <= n; i++){if(s[i] == '1'){if(cnt < k){vis[i] = true;res += (n - i + 1) * p;cnt++;}else res -= (n - i + 1) * r;}}for(int i = 1; cnt < k; i++){if(!vis[i]){vis[i] = true;res += (n - i + 1) * p;cnt++;}}ans = res;for(int ll = 1, rr = n; ll < rr;){if(vis[ll]) ll++;else if(!vis[rr]) rr--;else{res += (n - ll + 1) * p - (n - rr + 1) * r - (n - rr + 1) * p;ans = max(ans, res);vis[rr] = 0, vis[ll] = 1;}}cout << ans << endl;
}signed main(){solve();return 0;
}

G. Max Pair Matching 思维

题目要求对给定2n2n2n个{a1,b1,a2,b2,…,an,bn}\{a_1, b_1, a_2, b_2, \dots, a_n, b_n\}{a1​,b1​,a2​,b2​,…,an​,bn​}进行两两顶点配对形成nnn条边,边权的计算方式为wij=max⁡(∣ai−aj∣,∣ai−bj∣,∣bi−aj∣,∣bi−bj∣)w_{ij} = \max(|a_i - a_j|, |a_i - b_j| , |b_i - a_j|, |b_i - b_j|)wij​=max(∣ai​−aj​∣,∣ai​−bj​∣,∣bi​−aj​∣,∣bi​−bj​∣)。要求边权和最大。

首先考虑拆绝对值号,不妨令ai<bia_i < b_iai​<bi​(读入时进行预处理),在权值和最大的前提下,显然会有nnn个aia_iai​产生负贡献,nnn个bib_ibi​产生正贡献。那么如何确定每个数对提供正贡献还是负贡献?

由于ai<bia_i < b_iai​<bi​一定成立,我们任取两对进行分析。要使得b2−a1>b1−a2b_2 - a_1 > b _ 1 - a_2b2​−a1​>b1​−a2​,显然需要a1+b1<a2+b2a_1 + b_1 < a_2 + b_2a1​+b1​<a2​+b2​。那么我们只需要根据ai+bia_i+b_iai​+bi​的大小进行排序,然后取前nnn个aia_iai​作为负贡献,取后nnn个bib_ibi​作为正贡献即可。

#include <bits/stdc++.h>
#define int long long
using namespace std;struct node{ int a, b, sum;node(int aa, int bb, int ss): a(aa), b(bb), sum(ss) {}const bool operator< (const node &x) const { return sum < x.sum; }
};std::vector<node> mp;inline void solve(){int n = 0; std::cin >> n;for(int i = 1; i <= (n << 1); i++){int a, b, sum; std::cin >> a >> b;if(a > b) std::swap(a, b);mp.emplace_back(node(a, b, a + b));}int ans = 0;std::sort(mp.begin(), mp.end());for(int i = 0; i <= n - 1; i++) ans -= mp[i].a;for(int i = n; i < (n * 2); i++) ans += mp[i].b;cout << ans << endl;
}signed main(){solve();return 0;
}

J. ABC Legacy 小模拟

首先,AAA一定充当左括号,所以数量必不能超过nnn。然后剩余的问题在于BBB要充当的角色。

我们可以发现,要完成配对,需要nnn个左括号和nnn个右括号。那么考虑选一部分BBB当左括号。显然对于左括号而言,根据贪心的思想越左越好,因此我们对于到补齐nnn个左括号范围内的BBB全部丢到队列里去,超出左括号的范围外的BBB当作右括号与AAA匹配掉。

然后对于一定充当右括号的CCC,我们按照队列的顺序逐个匹配即可。匹配的同时可以检查合法性。

#include <bits/stdc++.h>
#define int long long
using namespace std;const int N = 1e5 + 10;std::deque<int> q[3];
std::vector<std::pair<int, int>> ans;
//*-----------------------------------*//
#define fir first
#define sec second
#define mkp make_pair
//*----------------------------------*//
#define showYes cout << "YES\n"
#define showNo cout << "NO\n"
//*----------------------------------*//
inline void solve(){int n = 0; std::cin >> n;std::string s; cin >> s;int cnta = 0, cntb = 0, cntc = 0;for(auto x : s){if(x == 'A') cnta++;if(x == 'B') cntb++;if(x == 'C') cntc++;}int cntbc = n - cnta;if(cntbc < 0){ cout << "NO" << endl; return; }for(int i = 0; i < 2 * n; i++){if(s[i] == 'A') q[0].emplace_back(i);else if(s[i] == 'B'){if(cntbc){ q[1].emplace_back(i); cntbc--; }else{if(q[0].empty()) { showNo; return; }ans.emplace_back(std::mkp(q[0].back(), i));q[0].pop_back();}}else if(s[i] == 'C'){if(q[0].empty() && q[1].empty()) { showNo; return; }if(q[1].size()){ans.emplace_back(std::mkp(q[1].back(), i));q[1].pop_back();}else if(q[0].size()){ans.emplace_back(std::mkp(q[0].back(), i));q[0].pop_back();}}}showYes;for(auto x : ans) cout << x.fir + 1 << ' ' << x.sec + 1 << endl;
}signed main(){//int t = 0; cin >> t;//while(t--) solve();return 0;
}

K. Amazing Tree

给定一颗nnn个节点的树,可以从任意一个点开始dfsdfsdfs,求最小字典序的后续遍历。

首先,对于字典序最小的要求,我们一定是从叶结点中的最小值开始遍历的。我们可以记录每个节点的度,然后倒序寻找度为111的节点。

然后,我们对当前节点uuu进行讨论,我们有两种策略:

  • 认为当前节点不是根节点:先将子树按最小权排序。如果发现当前子树中的最大最小值小于uuu,那么显然此时输出uuu不是最优策略,所以此时应当先dfsdfsdfs第kkk个子树(当作父节点向上走),再将uuu加入答案。否则就先遍历前k−1k - 1k−1个子树,然后将uuu加入答案,再遍历最后一个子树;
  • 认为当前节点是根节点:先将子树按最小权排序,然后按照最小叶序依次dfsdfsdfs子树,最后将uuu加入答案。

可以发现在dfsdfsdfs时需要记录搜索的顺序,从而确定是否可以将子树作为父节点向上走。

#include <bits/stdc++.h>
#define int long long
using namespace std;const int N = 2e5 + 10, INF = 1e9 + 7;
vector<int> g[N], ans;#define pii pair<int, int>
#define mkp make_pair
#define fir first
#define sec secondint deg[N], w[N];inline void solve(){ans.clear();int n = 0; std::cin >> n;for(int i = 1; i <= n; i++) deg[i] = 0;for(int i = 0; i <= n + 1; i++) g[i].clear();for(int i = 1, u, v; i <= n - 1; i++){cin >> u >> v;g[u].emplace_back(v);g[v].emplace_back(u);deg[u]++, deg[v]++;}function<void(int, int)> getmin = [&](int u, int fa){bool flag = true;w[u] = INF;for(auto nxt : g[u]){if(nxt == fa) continue;flag = false;getmin(nxt, u);w[u] = min(w[u], w[nxt]);}if(flag) w[u] = u;};function<void(int, int, int)> dfs = [&](int u, int fa, int dir){vector<pii> sot;for(auto v : g[u]){if(v == fa) continue;sot.emplace_back(mkp(w[v], v));}if(!sot.size()) { ans.emplace_back(u); return; }sort(sot.begin(), sot.end());if(dir == 0){for(auto x : sot) dfs(x.sec, u, 0);ans.emplace_back(u);} else {for(int i = 0; i < sot.size() - 1; i++) dfs(sot[i].sec, u, 0);if(u > sot.back().fir) dfs(sot.back().sec, u, 0), ans.emplace_back(u);else ans.emplace_back(u), dfs(sot.back().sec, u, 1);}}; int st = 0;for(int i = n; i >= 1; --i) if(deg[i] == 1) st = i;getmin(st, 0);dfs(st, 0, 1);for(auto x : ans) cout << x << ' ';cout << "\n";
}signed main(){ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);int t = 0; std::cin >> t;while(t--) solve();return 0;
}

L. Jason ABC

给定长度为3n3n3n由{A,B,C}\{A,B,C\}{A,B,C}构成的字符串,每次操作可以选择一段连续的区间将其全部修改为{A,B,C}\{A, B, C\}{A,B,C}中的一个字符。要求你在最小操作次数下将给定的字符串修改为包含nnn个AAA、nnn个BBB以及nnn个CCC的字符串。求最小修改次数以及修改操作。

首先可以确定,最大修改次数不会超过222次:

首先我们预处理三个前缀cnt[i][3]cnt[i][3]cnt[i][3]分别表示到位置iii为止三个字母的前缀和。

  • 000次:已经符合要求,不需要再修改
  • 111次:只需要修改一个区间[L,R][L,R][L,R]即可。如果假设将区间[L,R][L,R][L,R]变为AAA,那么要求cnt[3×n][2]−(cnt[R][2]−cnt[L−1][2])=ncnt[3 \times n][2] - (cnt[R][2] - cnt[L - 1][2]) = ncnt[3×n][2]−(cnt[R][2]−cnt[L−1][2])=n且cnt[3×n][3]−(cnt[R][3]−cnt[L−1][3])=ncnt[3 \times n][3] - (cnt[R][3] - cnt[L - 1][3]) = ncnt[3×n][3]−(cnt[R][3]−cnt[L−1][3])=n。那么直接双指针找即可。
  • 222次:找到最小的pospospos,使得[1,pos][1, pos][1,pos]中出现次数最多的字符恰出现了nnn次。那么把后面直接修改两次改为剩余两个字符的两段即可。
#include <bits/stdc++.h>
using namespace std;const int N = 1e6 + 10;
int cnt[N][4];inline void solve(){int n = 0; cin >> n;string s; cin >> s; s = '@' + s;auto change1 = [&](char c){int x = (c - 'A' + 1) % 3 + 1, y = (c - 'A' + 2) % 3 + 1;for(int l = 1, r = 1; l <= 3 * n; ){if(l > r) r = l;while((cnt[r][x] - cnt[l - 1][x] < cnt[3 * n][x] - n || cnt[r][y] - cnt[l - 1][y] < cnt[3 * n][y] - n) && r <= 3 * n) r++;if(cnt[r][x] - cnt[l - 1][x] == cnt[3 * n][x] - n && cnt[r][y] - cnt[l - 1][y] == cnt[3 * n][y] - n){return cout << 1 << endl << l << ' ' << r << ' ' << c << endl, true;}else l++;}return false;};auto change2 = [&](char c, int maxc){   int x = (c - 'A' + 1) % 3, y = (c - 'A' + 2) % 3;char X = x + 'A', Y = y + 'A';cout << 2 << endl;cout << maxc + 1 << ' ' << maxc + n - cnt[maxc][x + 1]  << ' ' << X << endl;cout << maxc + n - cnt[maxc][x + 1] + 1 << ' ' << 3 * n << ' ' << Y << endl;};for(int i = 1; i <= 3 * n; i++){for(int j = 1; j <= 3; j++) cnt[i][j] = cnt[i - 1][j];if(s[i] == 'A') cnt[i][1]++;if(s[i] == 'B') cnt[i][2]++;if(s[i] == 'C') cnt[i][3]++;}if(cnt[3 * n][1] == cnt[3 * n][2] && cnt[3 * n][2] == n){ std::cout << "0\n"; return; }if(change1('A') || change1('B') || change1('C')) return;int maxc = 0;char maxch;for(int i = 1; i <= 3 * n; i++) if(!maxc && cnt[i][s[i]-'A' + 1] == n) maxc = i, maxch = s[i];change2(maxch, maxc);
}signed main(){solve();return 0;
}

N. A-series 思维

有n+1n + 1n+1种,每种纸iii的大小是第i+1i + 1i+1张纸大小的两倍。

现在给你每种纸的数量,每次你可以选择一张纸对其进行对折,然后剪成两半。问能否通过剪操作变为目标纸张数量。

如果正着剪,显然会爆longlonglong\ longlong long。那么不妨考虑倒序合并目标纸张。看够不够。

#include <bits/stdc++.h>
#define int long long
using namespace std;const int N = 2e5 + 10;
int a[N], b[N];inline void solve(){int n = 0, ans = 0; std::cin >> n;for(int i = 1; i <= n + 1; i++) cin >> a[i];for(int i = 1; i <= n + 1; i++) cin >> b[i];for(int i = n + 1; i > 1; --i){int left = b[i] - a[i];if(left < 0) continue;(left += 1) >>= 1,b[i] -= left * 2, b[i - 1] += left; //向上取整合并纸张ans += left; //计数}for(int i = 1; i <= n; i++){if(b[i] > a[i]){ cout << -1 << endl; return; } //检查够不够}cout << ans << endl;
}signed main(){solve();return 0;
}

2021 ICPC Southeastern Europe Regional Contest ABFGJKLN相关推荐

  1. 2021 ICPC Southeastern Europe Regional Contest Werewolves(树上背包)

    2021 ICPC Southeastern Europe Regional Contest Werewolves(树上背包) 链接 题意:给出一个n个节点的树(n≤3000n\le3000n≤300 ...

  2. 2021 ICPC Southeastern Europe Regional Contest(更新至六题)

    2021 ICPC Southeastern Europe Regional Contest A题签到 A. King of String Comparison 题意:给两个字符串,找出有多少对(l, ...

  3. 2021 ICPC Southeastern Europe Regional Contest 树上dfs+思维

    |–>传送门<–| 题目大意 给定一颗nnn个节点的树,可以从任意一个点开始dfsdfsdfs,求最小字典序的后续遍历. 题解 首先,对于字典序最小的要求,我们一定是从叶结点中的最小值开始 ...

  4. 【题目记录】——The 2021 ICPC Asia Jinan Regional Contest

    文章目录 C Optimal Strategy 组合数 H Game Coin K Search For Mafuyu 欧拉序列 题目集地址 The 2021 ICPC Asia Jinan Regi ...

  5. ICPC Central Europe Regional Contest 2019 K. K==S(AC自动机+矩阵快速幂)

    Progressive hard octave rock tunes (so-called "phorts") are written using a specifific mus ...

  6. 2020-2021 ICPC Southeastern European Regional Programming Contest (SEERC 2020)

    2020-2021 ICPC Southeastern European Regional Programming Contest (SEERC 2020) B. Reverse Game 题目描述: ...

  7. The 2019 ICPC Asia Shanghai Regional Contest

    The 2019 ICPC Asia Shanghai Regional Contest 题号 题目 知识点 A Mr. Panda and Dominoes B Prefix Code C Maze ...

  8. 2018 ICPC Asia Jakarta Regional Contest

    2018 ICPC Asia Jakarta Regional Contest 题号 题目 知识点 难度 A Edit Distance B Rotating Gear C Smart Thief D ...

  9. The 2021 ICPC Asia Regionals Online Contest (I)

    The 2021 ICPC Asia Regionals Online Contest (I) 写了一晚上,日- 文章目录 一. A Busiest Computing Nodes 二.D Edge ...

最新文章

  1. go 语言 链表 的增删改查
  2. 5分钟实现SpringBoot整合Dubbo构建分布式服务
  3. R语言glm拟合logistic回归模型:模型评估(模型预测概率的分组密度图、混淆矩阵、准确率、精确度、召回率、ROC、AUC)、PRTPlot函数获取logistic模型最优阈值(改变阈值以优化)
  4. 杭电2669拓展欧几里得
  5. 本机用域名不能访问_域名注册申请网站域名注意事项
  6. asp.net控件开发基础(19)
  7. linux下rip服务启动失败,RIP协议_linux系统管理与服务的技术博客_51CTO博客
  8. linux 中文ssid 显示,无法连接中文 SSID 的 Wi-Fi?简单几步就搞定!
  9. 价值50万年薪的Java面试题
  10. 马云、马化腾任职清华;微软将数据保存在玻璃中;Visual Studio Online 上线 | 极客头条...
  11. html 设置font size,css font-size属性说明
  12. Python入门--面向对象的特征-->封装
  13. Remoting整理
  14. Abaqus槽钢杆受力有限元分析
  15. 震撼人心的战争类背景音乐
  16. 线性子空间和仿射子空间
  17. Angular中nz-select实现两个选择框互相关联
  18. python分析红楼梦出现的虚词词频统计,python对红楼梦的每一章节进行词频统计
  19. 微信游戏奇迹暖暖选取服务器失败,奇迹暖暖微信区为什么登不上_奇迹暖暖微信区登不上解决办法-66街机网...
  20. html隐藏visibility,CSS Visibility(可见性)

热门文章

  1. 施工企业安全教育培训数字化解决方案
  2. powerdesigner16.5破解补丁
  3. python小玩意——星座表程序
  4. 完全重映射和部分重映射分析(超详细)
  5. 计算2的100000次方
  6. Auto-Icon:一款自动代码生成工具 | 开发​工程师必备
  7. 计算机网络应用层之HTTP协议
  8. android修改输出分辨率,编译Android8.1修改默认分辨率和屏幕密度
  9. 获取手机的设备信息和唯一ID
  10. 建立一个网站,只需懂这一招