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

news2024/11/19 23:34:45

在这里插入图片描述

T1 如此编码

思路

由公式
在这里插入图片描述
和前缀乘积定义
在这里插入图片描述
m = b 1 + a 1 × b 2 + ⋅ ⋅ ⋅ + a 1 × a 2 × ⋅ ⋅ ⋅ × a n − 1 × b n m=b_1+a_1\times b_2+···+a_1\times a_2\times···\times a_{n-1}\times b_n m=b1+a1×b2+⋅⋅⋅+a1×a2×⋅⋅⋅×an1×bn
上述公式可以提取公共乘项 a i a_i ai,写成 m = ( b n b n − 1 ⋅ ⋅ ⋅ b 1 ) a m=(b_nb_{n-1}···b_1)_{a} m=(bnbn1⋅⋅⋅b1)a,类似 k k k进制表达,但每一位权的变化倍数不是常数 k k k,而是 a k a_k ak,对于 b [ i ] b[i] b[i]的求解,类比10进制转 k k k进制,将 k k k替换为 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) (mx)的钱最多买几本书。

代码

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 吉祥物投票

思路

看见区间赋值操作且维护区间长度为 1 e 9 1e9 1e9,很容易想到珂朵莉树,用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[],标签 i i i所对应的v值为lazy[i],对于操作2,交换lazy[x]lazy[y];而对于操作2,我们引入并查集,将多个v值映射到一个懒标记lazy[w]上,此时标签 i i i所对应的v值可能有多个,满足find(v)=lazy[i],同时lazy[x]赋一个从未使用过的数字即可,另外我们维护从懒标记到标签的映射inv[]

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

taglazyfa
111
222
333

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

taglazyfa
121
212
333

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

taglazyfa
122
242
333
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}); // 1e9

    int 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';
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/147652.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

一文搞懂内存映射原理及使用方法

a. 内存映射原理内存映射即在进程的虚拟地址空间中创建一个映射&#xff0c;分为两种&#xff1a;文件映射&#xff1a;文件支持的内存映射&#xff0c;把文件的一个区间映射到进程的虚拟地址空间&#xff0c;数据源是存储设备上的文件。匿名映射&#xff1a;没有文件支持的内存…

2. 因子(factor)、缺失数据(na)、字符串、时间序列数据

课程视频链接&#xff1a;https://www.bilibili.com/video/BV19x411X7C6?p1 本笔记参照该视频&#xff0c;笔记顺序做了些调整【个人感觉逻辑顺畅】&#xff0c;并删掉一些不重要的内容 系列笔记目录【持续更新】&#xff1a;https://blog.csdn.net/weixin_42214698/category_…

字符的编码与乱码

目录 前言 1 计算机中字符的编码分类 1.1 常见非Unicode编码 1.1.1 ASCII 1.1.2 ISO 8859-1 1.1.3 Windows-1252 1.1.4 GB2312 1.1.5 GBK 1.1.6 GB18030 1.1.7 Big5 1.1.8 编码汇总 1.2、Unicode编码 1.2.1 UTF-32 1.2.2 UTF-16 1.2.3 UTF-8 1.2.4 Unicode编码…

A1032 Sharing

Powered by:NEFU AB-IN Link 文章目录A1032 Sharing题意思路代码A1032 Sharing 题意 To store English words, one method is to use linked lists and store a word letter by letter. To save some space, we may let the words share the same sublist if they share the s…

2032.1.7 学习总结

1.string与int之间的相互转化问题 &#xff08;1&#xff09;int转string&#xff1a;使用to_string函数 引入头文件: #include<string> 转int&#xff0c;float&#xff0c;double都可以 string to_string (int val); string to_string (long val); string to_string…

Java外卖点餐系统小程序+数据库源码(带本地部署搭建文档)源码免费分享!

亲测Java在线点餐系统小程序数据库源码带本地部署搭建文档 需要源码学习可私信我获取。 小程序外卖扫码点餐为客户提供的是最方便的饮食方式,以快速、便捷的点餐业务送货上门为 -客户服务,这省去了客户很多不必要的时间和麻烦,给商家带来更多利益。同时,小程序外卖扫码点餐可…

STM32从固件库到HAL库

让坚持成为一种热爱&#xff0c;极致成为一种精神。历时10个月&#xff0c;目前我又重新回到了程序员的身份&#xff0c;2023想玩不一样的嵌入式。&#x1f680; 目录前言一、安装STM32CubeMX二、配置自己的HAL库MDK工程三、HAL库与固件库的区别1.句柄2.回调函数3.时钟配置4.HA…

Bulma - 免费开源的纯 CSS 前端 UI 框架,专注于构建移动优先的响应式 web 界面

简单易用的 CSS 框架&#xff0c;虽然只有一个 CSS 文件&#xff0c;但功能很强大&#xff0c;在国外很受开发者欢迎&#xff0c;推荐给大家。 关于 Bulma CSS 框架 Bulma 是一个简单、很容易自定义的 CSS UI 框架&#xff0c;提供了众多预定义好的样式&#xff0c;开发者可以…

宠物吸毛器控制板开发,构建理想人宠共居空间

目前养宠物的人越来越多&#xff0c;猫狗等宠物一直存在着严重的掉毛情况&#xff0c;宠物毛发可能会引起过敏等疾病反应&#xff0c;日常生活中清理工作是一大难题&#xff0c;市面上关于宠物的吸毛产品非常的少&#xff0c;为此沐渥开发了一款宠物吸毛器控制板&#xff0c;适…

奇怪,郭德纲小儿子八岁生日,现场照片发布不久却被删除了

2022年1月5日&#xff0c;对于北京德云社来说&#xff0c;是一个双喜临门好日子&#xff0c;首先德云社相声春晚开始录制&#xff0c;其次郭德纲的儿子郭汾阳&#xff0c;也要过八岁生日了。郭汾阳作为德云社的少班主&#xff0c;是郭德纲老师和董事长王惠所生&#xff0c;老来…

与ChatGPT的聊天:如何使用Python连接Neo4j并创建无向图?

0. 前言 尝试请ChatGPT帮写代码&#xff1a; 但发现ChatGPT可以给出逻辑上正确的程序&#xff0c;一旦具体深入询问&#xff0c;有可能会产生错误。 当然&#xff0c;也可能因为提问的人比较少&#x1f923; 不管怎么说&#xff0c;这篇可以当成是对ChatGPT茶余饭后的谈资&am…

数据库,计算机网络、操作系统刷题笔记28

数据库&#xff0c;计算机网络、操作系统刷题笔记28 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle…

产品重要更新: GcExcel Java Edition 6.0.2 Crack

重要产品更新&#xff1a; JDK 6 和 7 已经走到了生命的尽头。自此&#xff0c; GcExcel Java Edition将不再支持它们&#xff0c;现在将从最新的v6 版本及更高版本开始以JDK 8为目标。GcExcel Java Edition 6.0.2 Crack by Ω578867473 GcExcel高速 Java Excel 电子表格 API …

Zookeeper简介

引言 在分布式环境下&#xff0c;如果舍弃SpringCloud&#xff0c;使用其他的分布式框架&#xff0c;那么注册心中&#xff0c;配置集中管理&#xff0c;集群管理&#xff0c;分布式锁&#xff0c;分布式任务&#xff0c;队列的管理想单独实现怎么办。 Zookeeper介绍 Zookeeper…

Flink 运行架构

1 Flink 运行时的组件 Flink 运行时架构主要包括四个不同的组件&#xff0c;它们会在运行流处理应用程序时协同工作&#xff1a;作业管理器&#xff08;JobManager&#xff09;、资源管理器&#xff08;ResourceManager&#xff09;、任务管理器&#xff08;TaskManager&#…

一篇文章让你掌握HTML(下)

目录 1. 列表标签 1.1 无序列表 1.2 有序列表 1.3 自定义列表 2. 表格标签 2.1 表格的基本标签 2.2 表格相关属性 2.3 表格标题和表头单元格标签 2.4 表格的结构标签 2.5 合并单元格 3. 表单标签 3.1 input系列标签 3.1.1 input系列标签-文本框 3.1.…

MATLAB-非线性方程(组)求解

求非线性方程或方程组解的问题也就是求函数零点的问题。对于任意函数&#xff0c;在求解范围内可能有零点&#xff0c;也可能没有;可能只有一个零点&#xff0c;也可能有多个甚至无数个零点。MATLAB没有可以求解所有函数零点的通用命令&#xff0c;下面将分别讨论一元函数和多元…

Nginx入门知识

一、什么是NginxNginx (engine x) 是一个高性能的HTTP和反向代理web服务器&#xff0c;Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件&#xff08;IMAP/POP3&#xff09;代理服务器&#xff0c;在BSD-like 协议下发行。其特点是占有内存少&#xff0c;并发能力强&am…

JavaScript 字符串

文章目录JavaScript 字符串JavaScript 字符串字符串长度特殊字符字符串可以是对象字符串属性和方法字符串属性字符串方法JavaScript 字符串 JavaScript 字符串用于存储和处理文本。 JavaScript 字符串 字符串可以存储一系列字符&#xff0c;如 “John Doe”。 字符串可以是插…

如何连接远程mysql数据库(原创)

一、连接远程数据库&#xff1a;&#xff08;前提本地也有mysql的客户端&#xff09; 1、显示密码 如&#xff1a;MySQL 连接远程数据库&#xff08;192.168.5.116&#xff09;&#xff0c;端口“3306”&#xff0c;用户名为“rfid_hh”&#xff0c;密码“123456” C:/>mysq…