T1 如此编码

思路

由公式

和前缀乘积定义

得m=b1+a1×b2+⋅⋅⋅+a1×a2×⋅⋅⋅×an−1×bnm=b_1+a_1\times b_2+···+a_1\times a_2\times···\times a_{n-1}\times b_nm=b1​+a1​×b2​+⋅⋅⋅+a1​×a2​×⋅⋅⋅×an−1​×bn​,
上述公式可以提取公共乘项aia_iai​,写成m=(bnbn−1⋅⋅⋅b1)am=(b_nb_{n-1}···b_1)_{a}m=(bn​bn−1​⋅⋅⋅b1​)a​,类似kkk进制表达,但每一位权的变化倍数不是常数kkk,而是aka_kak​,对于b[i]b[i]b[i]的求解,类比10进制转kkk进制,将kkk替换为a[i]a[i]a[i]即可。

代码

void solve() {int n, m;cin >> n >> m;vector<int> a(n), b(n);for (int i = 0; i < n; i++) cin >> a[i];for (int i = 0; i < n; i++) {b[i] = m % a[i];m /= a[i];}for (int i = 0; i < n; i++) cout << b[i] << ' ';cout << '\n';
}

T2 何以包邮?

思路

背包问题,问题等价于求(m−x)(m-x)(m−x)的钱最多买几本书。

代码

void solve() {int n, x; cin >> n >> x;vector<int> a(n);int sum = 0;for (int i = 0; i < n; i++) cin >> a[i], sum += a[i];int v = sum - x;vector<int> dp(v + 1, 0);for (int i = 0; i < n; i++) {for (int j = v; j >= 0; j--) {if (j >= a[i]) {dp[j] = max(dp[j], dp[j - a[i]] + a[i]);}}}cout << sum - dp[v] << '\n';
}

T4 吉祥物投票

思路

看见区间赋值操作且维护区间长度为1e91e91e9,很容易想到珂朵莉树,用set维护一系列区间。

珂朵莉树模板

  • 结构体nodevmutable修饰,访问容器set时迭代器const修饰,只读,通过该mutable使得整个结构体只读时该成员仍可变,为后面区间加操作铺垫。
  • split()将区间从pos处断开,并返回以pos为左端点的迭代器。这里首先调用set自身的二分方法lower_bound()找到左端点不小于pos的区间,找到后判断it->l == pos,若满足则不需要断开区间,直接返回;否则pos在前面一个区间中,将该区间断开为node(L, pos - 1, V)node(pos, R, V),重新插入容器,insert方法成功插入后返回迭代器,返回该对象。
  • assign()区间赋值,这里先split(r+1)获取结束端点是因为(r+1)可能在begin指向区间,操作使迭代器begin失效。之后erase(begin,end),插入新区间即可。
struct node {ll l ,r;mutable ll v;node(ll l, ll r, ll v) : l(l), r(r), v(v) {}bool operator<(const node &a) const { return l < a.l; }
};set<node> tree;set<node>::iterator split(ll pos) {auto it = tree.lower_bound(node(pos, 0, 0));if (it != tree.end() && it->l == pos)return it;it--;ll L = it->l, R = it->r, V = it->v;tree.erase(it);tree.insert(node(L, pos - 1, V));return tree.insert(node(pos, R, V)).first;
}void assign(ll l, ll r, ll v) {auto end = split(r + 1), begin = split(l);tree.erase(begin, end);tree.insert(node(l, r, v));
}

部分分做法

用一个数组cnt[]维护每个作品的得票,在assign操作时实时更新,这样可以O(1)O(1)O(1)回应操作4,查询每个作品的得票。
对于操作2,3,暴力O(m)O(m)O(m)访问容器内所有段,修改v值,由于mutable关键字我们可以直接通过迭代器修改。
对于操作5,开一个map,暴力O(m)O(m)O(m)访问容器内所有段,统计最大者。
这样可以得45分。

全部分做法

① 首先,用set维护区间最大值,O(1)O(1)O(1)回应操作5,这个在之前的3月份的第四题通信管理中也用到过,详见我的博客CSP22.3 T4通信系统管理;
② 对于操作2,3,我们并不需要真的修改容器内的值,只需要改变标签和v值的映射即可,一种懒惰更新方法,开一数组lazy[],标签iii所对应的v值为lazy[i],对于操作2,交换lazy[x]lazy[y];而对于操作2,我们引入并查集,将多个v值映射到一个懒标记lazy[w]上,此时标签iii所对应的v值可能有多个,满足find(v)=lazy[i],同时lazy[x]赋一个从未使用过的数字即可,另外我们维护从懒标记到标签的映射inv[]

举个例子:
假设set中维护了以下段:(1,3,2),(4,5,1),(6,9,3),(10,12,2),此时还未执行过操作2,3,标签和lazyfa层之间的映射为

tag lazy fa
1 1 1
2 2 2
3 3 3

执行操作3 1 2后,容器内容不变:

tag lazy fa
1 2 1
2 1 2
3 3 3

这时统计标签为1的段,应该统计val值满足lazy[1]=2的段,执行操作2 2 1之后,容器同样不变,而映射变为:

tag lazy fa
1 2 2
2 4 2
3 3 3
4

统计标签为1的段,应统计val值满足find(val)=lazy[1]=2的段,即val值为1,2的段。

有一个地方我调了很久,就是操作5中输出最多得票的编号最小者,这个编号经过层层映射,早已不是容器内v值,或者find(v),而是对应标签inv[find(v)]的最小者,由于我们插入时已经取了find(v),保证v==find(v),因此将所有最多得票者的inv[v]中取最小输出答案。

代码

struct node {int l ,r;mutable int v;node(int l, int r, int v) : l(l), r(r), v(v) {}bool operator < (const node &a) const { return l < a.l; }
};struct pp
{int k, v;bool operator < (const pp& a) const {if (v != a.v) return v > a.v;return k < a.k;}
};set<node> tree;     // Chthollty tree
int lazy[200005], cnt[200005], fa[200005];
map<int , int> inv;     // 建立标记和标签之间双射
set<pp> all;  // 维护区间最值int _find(int x) {if (x == fa[x]) return x;return (fa[x] = _find(fa[x]));
}void _union(int x, int y) {fa[_find(y)] = _find(x);
}set<node>::iterator split(int pos) {auto it = tree.lower_bound(node(pos, 0, 0));if (it != tree.end() && it->l == pos)return it;it--;int L = it->l, R = it->r, V = it->v;tree.erase(it);tree.insert(node(L, pos - 1, V));return tree.insert(node(pos, R, V)).first;
}void assign(int l, int r, int v) {auto end = split(r + 1), begin = split(l);int tv; // 标记可能被操作2合并至另一个标记,fa[]存储真实标记for (auto it = begin; it != end; it++) {tv = _find(it->v);all.erase({tv, cnt[tv]});cnt[tv] -= (it->r - it->l + 1);all.insert({tv, cnt[tv]});}tree.erase(begin, end);tv = _find(v);tree.insert(node(l, r, tv));all.erase({tv, cnt[tv]});cnt[tv] += (r - l + 1);all.insert({tv, cnt[tv]});
}void solve() {int n, m, q; cin >> n >> m >> q;int tot = m;tree.insert(node(1, n, 0));for (int i = 0; i <= max(2 * m, 2 * q); i++) lazy[i] = fa[i] = i;for (int i = 1; i <= m; i++) inv[i] = i;cnt[0] = n;all.insert({0, n}); // 1e9int op, l, r, x, w, y;while (q--) {cin >> op;if (op == 1) {cin >> l >> r >> x;assign(l, r, lazy[x]);}else if (op == 2) {cin >> x >> w;int fx = lazy[x], fy = lazy[w];all.erase({fx, cnt[fx]});all.erase({fy, cnt[fy]});cnt[fy] += cnt[fx];   // 标记lazy[x]弃用all.insert({fy, cnt[fy]});_union(fy, fx);lazy[x] = ++tot, inv[tot] = x;  // 创建一个新标记}else if (op == 3) {cin >> x >> y;swap(inv[lazy[x]], inv[lazy[y]]);swap(lazy[x], lazy[y]);}else if (op == 4) {cin >> w;cout << cnt[lazy[w]] << '\n';}else if (op == 5) {int ans = 0, ansi = 0;for (auto it : all) {if (it.k && it.v > ans) {ans = it.v;ansi = inv[it.k];}if (it.k && it.v == ans && inv[it.k] < ansi) ansi = inv[it.k];if (ans > it.v) break;}cout << ansi << '\n';}}
}

2022年9月CSP认证题解 如此编码(k进制),何以包邮?(背包问题),吉祥物投票(珂朵莉树、懒标记、并查集)相关推荐

  1. CSP认证题解第一题

    文章目录 202012-1 期末预测之安全指数 202009-1 称检测点查询 202006-1 线性分类器 201912-1 报数 201909-1 小明种苹果 201903-1 小中大 20181 ...

  2. 洛谷P1017题解 [NOIP2000 提高组] 进制转换

    原文地址:https://luvletter.blog.luogu.org/p1017-ti-jie P1017 [NOIP2000 提高组] 进制转换 题目描述 我们可以用这样的方式来表示一个十进制 ...

  3. 2019年3月CCF CSP 认证题解第一题

    第一题:201903-1 [题目背景] 在数据分析中,最小值最大值以及中位数是常用的统计信息. [题目描述] 老师给了你n个整数组成的测量数据,保证有序(可能为升序或降序),可能存在重复的数据.请统计 ...

  4. 2021 12月CSP认证心得

    考前 差不多考前两个月开始准备,每个周都刷一些csp往年的题目,或者每个周都刷一些算法题,就这样一直到了最后一个周,害,每次考试前都会放纵一下自我,无论啥考试都不例外,最后一个周也松懈了一下下,不过还 ...

  5. CSP认证题解第二题

    文章目录 202012-2 期末预测之最佳阈值 202009-2 风险人群 201909-2 小明种苹果(续) 201903-2 二十四点 201812-2 小明放学 201809-2 买菜 2018 ...

  6. CCF CSP认证 题解:201703-3 Markdown(Java语言原创)

    问题描述 Markdown 是一种很流行的轻量级标记语言(lightweight markup language),广泛用于撰写带格式的文档.例如以下这段文本就是用 Markdown 的语法写成的: ...

  7. 花神游历各国 题解(小清新线段树/树状数组+并查集)

    题面 众所周知,这是一道小清新线段树 然而可以用树状数组水过去且跑得飞快 看到区间开方第一反应肯定是线段树懒标记区间修改之类的,但是这个东西似乎确凿不可维护 所以考虑暴力循环单点修改->T飞 于 ...

  8. 【题解】洛谷P1066 [NOIP2006TG] 2^k进制数(复杂高精+组合推导)

    洛谷P1066:https://www.luogu.org/problemnew/show/P1066 思路 挺难的一道题 也很复杂 满足题目要求的种数是两类组合数之和 r的最多位数m为 w/k(当w ...

  9. C认证笔记 - 计算机通识 - 进制转换

    计算机通识 - 目录指引 计算机通识 1:进制转换 1.0 任务目标 1.1 进制的定义 1.2 各进制间的转换方法 1.2.1 「二进制」转「十进制」 1.2.2 「二进制」转「八进制」 1.2.3 ...

最新文章

  1. asp.net断点续传技术
  2. Linux(64位)下OpenBabel 2.4.1、python2.7和Ipython实战(三)
  3. linux下如何将mysql加入环境变量
  4. ubuntu下小键盘不能用
  5. org.apache.ibatis.binding.BindingException原因总结
  6. Java 查找指定类型的数组元素
  7. python requests 示例_Python Requests模块的简单示例
  8. Java SE 6.0编程指南_Java SE 6.0 编程指南(附光盘)
  9. 如何将瀑布流里的图片加链接_只需5步!魔幻丛林瀑布后期揭秘
  10. android应用程序开发_深圳app开发公司:跨平台应用程序开发工具有哪些?
  11. android自定义viewgroup之我也玩瀑布流
  12. 华三交换机mode是什么意思_POE交换机150米、长距离250米传输是什么意思?
  13. Tideways+Xhgui搭建非侵入式php监控平台
  14. angular要多久学会_成为优秀Angular开发者所需要学习的19件事
  15. webpack+vue解决前端跨域问题
  16. python学习笔记7-读取pdf并输出到excel
  17. ​新手到底如何入门PLC?
  18. vscode下搭建vue项目
  19. ad7606中文资料_AD7606-6 pdf,AD7606-6中文资料,AD7606-6应用电路-华秋商城
  20. 隐语义模型(Latent Factor Model, LFM)原理以及代码实现

热门文章

  1. github-july-回文判断
  2. 使用deepdive来做因子图推理
  3. 【TV Picture Quality - 05】TV PQ术语汇总
  4. 危化行业人员定位系统解决方案,减少人员伤亡-新导智能
  5. 光环国际PMP:项目经理如何回答“这个项目要多久完成?”
  6. 一个比较齐全的汉字字库对应拼音 操作实现
  7. python电脑安装教程_python详细安装教程
  8. jsp中的java代码怎样调试
  9. win7备份工具_Win7/10系统如何一键还原系统?一键备份还原系统方法图文教程
  10. mysql基于SpringBoot小而学在线考试系统毕业设计源码141507