Educational Codeforces Round 142
写在前面
比赛地址:https://codeforces.com/contest/1792。
我是超级大鸽子咕咕咕
A
当且仅当有两个怪物初始血量为 1 时使用操作 1,否则用操作 2。
复制复制//By:Luckyblock /* */ #include <cstdio> #include <cctype> #include <algorithm> //============================================================= //============================================================= inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0'; return f * w; } //============================================================= int main() { // freopen("1.txt", "r", stdin); int T = read(); while (T --) { int n = read(); int num1 = 0, num2 = 0; for (int i = 1; i <= n; ++ i) { int h = read(); num1 += (h == 1); num2 += (h != 1); } int ans = num1 / 2; ans += num2 + (num1 % 2 == 1); printf("%d\n", ans); } return 0; }
B
先把操作 1 全用了。若此时心情大于 1,则再交替使用操作 2、3,直至不能使得心情值保持不变。此时两人心情相同,且进行操作一定会使某人的心情不可逆地降低,此时至多可再进行心情 +1 次操作。
用完操作 1 后,两人的心情值之和无法增加。则应保证在心情值不变的情况下尽可能地多进行操作,并在心情值不得不下降时,使心情值较小的一方的心情尽可能大。则显然按上述的顺序进行操作是最优的。
//By:Luckyblock /* */ #include <cstdio> #include <cctype> #include <algorithm> //============================================================= //============================================================= inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0'; return f * w; } //============================================================= int main() { // freopen("1.txt", "r", stdin); int T = read(); while (T --) { int a[5] = {0}, ans, now; for (int i = 1; i <= 4; ++ i) a[i] = read(); now = ans = a[1]; int maxa = std::max(a[2], a[3]), mina = std::min(a[2], a[3]); if (now == 0) { if (a[2] || a[3] || a[4]) ++ ans; printf("%d\n", ans); continue; } ans += 2 * mina; maxa -= mina; if (now < maxa) { ans += now + 1; printf("%d\n", ans); continue; } ans += maxa; now -= maxa; if (now < a[4]) { ans += now + 1; printf("%d\n", ans); continue; } ans += a[4]; printf("%d\n", ans); } return 0; }
C
先手玩几组数据找找结论。以下将对元素 的一次操作简写为 ,将元素 位于位置 称为 在有序位置。
- 一种通用的操作顺序是:
- 当 1 或 不在有序位置时,必须在最后进行 使得它们有序。
- 对结论 1 进行扩展,当有任意的数不在有序位置时,都必须在最后进行 。因为其他的操作后 和 一定在无序位置。 同理,当有除 的数不在有序位置时,倒数第二次操作一定是 ;当有除 的数不在有序位置时,倒数第三次操作一定是 ……
- 综合结论 1、3 考虑,我们仅需找到结论 1 中操作序列中尽量靠后的一个位置,使得这个位置之前的操作对象们都是相对有序的。从该位置开始向后进行操作即可。
实现时记录每个数在排列中的位置,按照数的大小中间向两侧比较位置,检查是否相对有序即可。复杂度 级别。
//By:Luckyblock /* */ #include <cstdio> #include <cctype> #include <algorithm> const int kN = 2e5 + 10; //============================================================= int n, a[kN], pos[kN]; //============================================================= inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0'; return f * w; } //============================================================= int main() { // freopen("1.txt", "r", stdin); int T = read(); while (T --) { n = read(); for (int i = 1; i <= n; ++ i) { a[i] = read(); pos[a[i]] = i; } int lth = 0; int i, j; if (n % 2) { i = j = (n + 1) / 2; } else { i = n / 2, j = n / 2 + 1; } for (int fir = n, las = 1; i > 0 && j <= n; -- i, ++ j) { if (pos[i] <= pos[j] && pos[i] <= fir && pos[j] >= las) { if (i != j) ++ lth; } else { break; } fir = pos[i], las = pos[j]; } printf("%d\n", n / 2 - lth); } return 0; }
D
对于两个长度为 的排列 ,定义一种运算 。运算结果 也是一个长度为 的排列,且满足:。对于排列 定义其魅力值为满足 的最大的下标 。特别地,若 , 的魅力值为 0。
组数据,每组数据给定 个长度为 的排列 。对于所有 ,求 的魅力值的最大值。
,,,。
2S,256MB。
凭什么卡我 bitset 暴力啊(恼
发现定义的这个运算和矩阵乘法相当相似,不满足交换律,且满足结合律,证明可自己手玩。于是考虑矩阵乘法那一套:定义单位排列 ;对于排列 ,将满足 的排列 定义为排列 的逆排列,记作 。
再回到题目所求,若 的魅力度为 ,考虑变换一下:
上式等价于 和 的逆排列最长公共前缀为 。
综上,考虑求得排列 的逆排列,查询 的答案时在所有逆排列上匹配最长公共前缀即可。使用 Trie 即可简单实现。总复杂度 级别。
或者更加具体地,还可以从实际意义考虑逆排列的含义: 即排列 中 的位置。如果从等号右边往左边理解,上式的另一种解释是处理出每个排列中 的位置并按顺序组成一个新的排列 ,求这个新的排列与所有原排列的最长公共前缀。
注意清空 Trie 时要全部清空,并且数组开大点。两个错误叠起来 RE 变 WA 真是把我鲨了。
//By:Luckyblock /* */ #include <cstdio> #include <cctype> #include <cstring> #include <algorithm> const int kN = 5e4 + 10; const int kM = 11; //============================================================= int n, m, a[kN][kM], inv[kN][kM]; //============================================================= inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0'; return f * w; } namespace Trie { const int kNode = kN << 3; int num, tr[kNode][11]; void Init() { for (int i = 0; i <= num; ++ i) { memset(tr[i], 0, sizeof (tr[i])); } num = 0; } void Insert(int id_) { int now = 0; for (int i = 1; i <= m; ++ i) { int x = inv[id_][i]; if (!tr[now][x]) tr[now][x] = ++ num; now = tr[now][x]; } } int Query(int id_) { int now = 0, ret = 0; for (int i = 1; i <= m; ++ i) { int x = a[id_][i]; if (!tr[now][x]) break; ++ ret; now = tr[now][x]; } return ret; } } //============================================================= int main() { // freopen("1.txt", "r", stdin); int T = read(); while (T --) { n = read(), m = read(); Trie::Init(); for (int i = 1; i <= n; ++ i) { for (int j = 1; j <= m; ++ j) { a[i][j] = read(); inv[i][a[i][j]] = j; } Trie::Insert(i); } for (int i = 1; i <= n; ++ i) { printf("%d ", Trie::Query(i)); } printf("\n"); } return 0; }
E
组数据,每组数据给定参数 。对于 的约数 ,记满足 的最小的 为 ,求上述 的个数,并输出所有 的异或和。
,。
2.5S,256MB。
写了个 的质因数分解我是超级大啥b。
前置知识:约数个数的上界估计:https://www.cnblogs.com/ubospica/p/10392523.htm、https://blog.csdn.net/VFleaKing/article/details/88809335。
省流版: 内的数约数至多有 个。
于是考虑先对 进行质因数分解,再暴力凑出 的所有约数,问题变为对每一个约数 求得一组满足上述条件的 ,且满足 尽可能地小,则 应当是满足 的最大的 的约数。如果我们可以求得每个约数 对应的 ,那么只需检测 是否成立即可判断 是否对答案有贡献。
直接暴力枚举 的复杂度是无法承受的。考虑子集 DP。记 表示满足 的 的最大的约数。对于 ,显然有 ;对于 ,考虑枚举 的质因子 ,有:
的质因子的数量级只有 左右,DP 复杂度并不高。处理出 DP 值后累计有贡献的 即可。总复杂度约为 级别。
DP 时要注意实现,虽然出题人没卡,但直接用 map 让 作 的下标跑的相当慢。应当令 的编号作 的下标,转移时使用二分查找 即可。
//By:Luckyblock /* */ #include <cstdio> #include <cctype> #include <vector> #include <algorithm> #define LL long long const int kN = 1e5 + 1e4 + 10; //============================================================= int n, m1, m2, sz, ans1, f[kN]; LL ans2; std::vector <int> p, c; std::vector <LL> d; //============================================================= inline int read() { int f = 1, w = 0; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = - 1; for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + ch - '0'; return f * w; } void Init() { sz = ans1 = 0; ans2 = 0ll; p.clear(), c.clear(), d.clear(); n = read(), m1 = read(), m2 = read(); int temp1 = m1, temp2 = m2; for (int i = 2; i * i <= m1 || i * i <= m2; ++ i) { if (temp1 % i == 0 || temp2 % i == 0) { ++ sz; p.push_back(i), c.push_back(0); while (temp1 % i == 0) temp1 /= i, c[sz - 1] ++; while (temp2 % i == 0) temp2 /= i, c[sz - 1] ++; } } if (temp1 > temp2) std::swap(temp1, temp2); if (temp1 > 1) ++ sz, p.push_back(temp1), c.push_back(1); if (temp2 > 1 && temp1 == temp2) ++ c[sz - 1]; if (temp2 > 1 && temp1 != temp2) ++ sz, p.push_back(temp2), c.push_back(1); } void Dfs(int lth_, LL d_) { if (lth_ == sz) { d.push_back(d_); return ; } Dfs(lth_ + 1, d_); LL x = 1ll; for (int i = 1; i <= c[lth_]; ++ i) { x *= p[lth_]; Dfs(lth_ + 1, d_ * x); } } void DP(LL id_) { LL d_ = d[id_]; if (d_ <= n) { f[id_] = d_; return ; } f[id_] = 0; for (int i = 0; i < sz; ++ i) { if (d_ % p[i]) continue; for (int l = 0, r = id_ - 1; l <= r; ) { int mid = (l + r) >> 1; if (d[mid] == d_ / p[i]) { f[id_] = std::max(f[id_], f[mid]); break; } else if (d[mid] < d_ / p[i]) { l = mid + 1; } else { r = mid - 1; } } } } //============================================================= int main() { // freopen("1.txt", "r", stdin); int t = read(); while (t --) { Init(); Dfs(0, 1); std::sort(d.begin(), d.end()); for (int i = 0, dnum = d.size(); i < dnum; ++ i) { DP(i); if (f[i] && d[i] / f[i] <= n) { ++ ans1, ans2 ^= d[i] / f[i]; } } printf("%d %lld\n", ans1, ans2); } }
F
一个感觉没那么牛逼的计数 DP,但是鸽了,有空再说。
写在最后
- D 另一种理解中的的反向考虑。
- 质因数分解是 的。
- 内的数约数至多有 个。
- 10^9 内的数质因子至多有 个()。
最近 CF 一场连着一场还要学车还要抽空学杀软文化课防止挂科……走一步看一步吧你妈的,今晚还有场 Div3,现在手里屯了三套题没补完,我真是超级大鸽王。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具