第35次CCF计算机软件能力认证-5-木板切割

article/2025/6/8 5:33:54

 原题链接:

TUOJ

我自己写的35分正确但严重超时的代码

#include <bits/stdc++.h>
using namespace std;
int main()
{int n, m, k;cin >> n >> m >> k;vector<unordered_map<int, int>> mp(2);int y;for (int i = 1; i <= n; i++){cin >> y;mp[1][i] = y;}while (k--){int x, l, r;cin >> x >> l >> r;unordered_map<int, int> tmp;int color_num = 0, num = 0;unordered_set<int> color_type;int pos = -1;for (int i = l; i <= r; i++){if (mp[x].count(i)){int color = mp[x][i];tmp[i] = color;color_type.insert(color);if (pos == -1 || tmp[i] != tmp[pos])num++;pos = i;mp[x].erase(i);}}color_num = color_type.size();mp.push_back(tmp);cout << color_num << ' ' << num << endl;}
}

过了7个样例,35分,对于现在的我来说也还行

 

知道你们肯定不满足35分,特地给出了大佬写的代码,300行+,自己写一个数据结构,我只能说nb,水平有限,不作说明

CCF-CSP第35次认证第五题——木板切割【C++满分题解;平衡树set,线段树,分块预处理,位图;区间合并、懒更新与分治、位运算优化】_csp 木板切割-CSDN博客

#include <iostream>
#include <vector>
#include <set>
#include <algorithm>
#include <cstdint>
using namespace std;// ------------------------
// 线段树部分:支持查询区间内颜色段数、左右端颜色
// ------------------------// 线段树节点结构
struct SegmentTreeNode {int left, right;        // 节点区间 [left, right]int segment_count;      // 该区间内颜色段数(相邻颜色相同视为同一段)int left_color, right_color;  // 区间最左/最右的颜色SegmentTreeNode *left_child, *right_child;SegmentTreeNode(int l, int r): left(l), right(r), segment_count(1), left_color(0), right_color(0),left_child(nullptr), right_child(nullptr) {}
};// 建树:叶节点对应单个位置,其颜色直接取自 colors 数组
SegmentTreeNode* buildTree(const vector<int>& colors, int l, int r) {SegmentTreeNode* node = new SegmentTreeNode(l, r);if (l == r) {node->left_color = node->right_color = colors[l];node->segment_count = 1;return node;}int mid = (l + r) / 2;node->left_child = buildTree(colors, l, mid);node->right_child = buildTree(colors, mid + 1, r);node->left_color = node->left_child->left_color;node->right_color = node->right_child->right_color;// 初步合并左右子区间的段数node->segment_count = node->left_child->segment_count + node->right_child->segment_count;// 如果左右子区间的边界颜色相同,则合并为一段if (node->left_child->right_color == node->right_child->left_color) {node->segment_count--;}return node;
}// 查询区间 [l, r] 的颜色段数以及左右端颜色
void query(SegmentTreeNode* node, int l, int r, int& segment_count, int& first_color, int& last_color) {if (node == nullptr || node->right < l || node->left > r) {segment_count = 0;first_color = -1;last_color = -1;return;}if (l <= node->left && node->right <= r) {segment_count = node->segment_count;first_color = node->left_color;last_color = node->right_color;return;}int left_seg = 0, right_seg = 0;int left_first = -1, left_last = -1;int right_first = -1, right_last = -1;query(node->left_child, l, r, left_seg, left_first, left_last);query(node->right_child, l, r, right_seg, right_first, right_last);if (left_seg == 0) {segment_count = right_seg;first_color = right_first;last_color = right_last;} else if (right_seg == 0) {segment_count = left_seg;first_color = left_first;last_color = left_last;} else {segment_count = left_seg + right_seg;if (left_last == right_first) segment_count--;first_color = left_first;last_color = right_last;}
}// ------------------------
// 块状分解部分:预处理整个颜色数组以快速回答区间内“不同颜色数”查询  
// 用 64 位整数数组模拟 bitset,每一位表示某种颜色是否出现。
// ------------------------int B;            // 块大小(可调)
int numBlocks;    // 总块数
int W;            // 每个 bitset 需要的 64 位整数数量(W = ceil(m/64))
vector<int> colors;  // 颜色数组(1-indexed)
vector<vector<uint64_t>> blockOR;  // 每块预处理的“或”结果// 查询区间 [L,R] 内颜色的 bitset(即各颜色是否出现的标记),返回大小为 W 的 uint64_t 数组
vector<uint64_t> distinctQuery(int L, int R) {vector<uint64_t> res(W, 0ULL);int startBlock = (L - 1) / B;int endBlock = (R - 1) / B;if (startBlock == endBlock) {// 区间完全落在同一块,直接遍历求或for (int i = L; i <= R; i++) {int col = colors[i];int idx = col - 1;res[idx / 64] |= (1ULL << (idx % 64));}} else {// 处理起始块的部分int blockStartEnd = (startBlock + 1) * B;for (int i = L; i <= blockStartEnd; i++) {int col = colors[i];int idx = col - 1;res[idx / 64] |= (1ULL << (idx % 64));}// 处理中间整块for (int b = startBlock + 1; b < endBlock; b++) {for (int j = 0; j < W; j++) {res[j] |= blockOR[b][j];}}// 处理结束块的部分int endBlockStart = endBlock * B + 1;for (int i = endBlockStart; i <= R; i++) {int col = colors[i];int idx = col - 1;res[idx / 64] |= (1ULL << (idx % 64));}}return res;
}// 将 src 的 bitset 结果“或”到 dest 上
void unionBitset(vector<uint64_t>& dest, const vector<uint64_t>& src) {for (int i = 0; i < W; i++) {dest[i] |= src[i];}
}// 统计 bitset 中 1 的个数,即不同颜色数
int countBits(const vector<uint64_t>& bs) {int cnt = 0;for (auto x : bs) {cnt += __builtin_popcountll(x);}return cnt;
}// ------------------------
// 主函数
// ------------------------
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);int n, m, k;cin >> n >> m >> k;// colors 数组采用 1-indexed,下标 1~ncolors.resize(n + 1);bool allDistinct = true; // 标记是否所有颜色都不相同(即 c[i] = i 的情况),用于特殊情况优化for (int i = 1; i <= n; i++) {cin >> colors[i];if (colors[i] != i)allDistinct = false;}// 构建线段树(当 allDistinct 为 true 时,本质上不用查询区间信息,但为了代码统一构造)SegmentTreeNode* root = buildTree(colors, 1, n);// ------------------------// 块状分解预处理:构造每块的颜色“或”信息// ------------------------B = 512;  // 块大小(可根据实际情况调节)numBlocks = (n + B - 1) / B;// 每个 bitset 长度为 W = ceil(m/64)W = (m + 63) / 64;blockOR.assign(numBlocks, vector<uint64_t>(W, 0ULL));for (int b = 0; b < numBlocks; b++) {int L = b * B + 1;int R = min(n, (b + 1) * B);for (int i = L; i <= R; i++) {int col = colors[i];int idx = col - 1;blockOR[b][idx / 64] |= (1ULL << (idx % 64));}}// ------------------------// 每块木板维护一个 set,记录当前木板上存在的区间(区间端点均为原数组下标)// 初始时 1 号木板包含整个区间 [1, n]// ------------------------// 用 pair<int, int> 表示一个区间 [first, second]vector<set<pair<int, int>>> boards(k + 2);  // 共 k+1 号木板,编号 1~k+1boards[1].insert({1, n});// 处理 k 次切割操作// 每次输入 x, l, r 表示对木板 x 的区间 [l, r] 进行切割,// 切下来的部分构成新的木板,输出:切下部分的不同颜色数 和 颜色段数(合并相邻颜色相同的段后)for (int op = 1; op <= k; op++) {int x, l, r;cin >> x >> l >> r;set<pair<int, int>>& current = boards[x];// 收集本次切割中,被切下来的区间vector<pair<int, int>> cut_segments;// 在当前木板的区间集合中找到所有与 [l, r] 有交集的区间auto it = current.lower_bound({l, 0});if (it != current.begin()) --it;while (it != current.end()) {int s = it->first, e = it->second;if (s > r) break;  // 后面的区间起点超过 r,无需继续if (e < l) { // 当前区间完全在 [l, r] 之前++it;continue;}// 求交集int a = max(s, l), b = min(e, r);if (a <= b) {cut_segments.push_back({a, b});// 从当前木板中移除该区间,并将剩余部分(若有)重新加入auto temp = it;++it;current.erase(temp);if (s < a) {current.insert({s, a - 1});}if (b < e) {current.insert({b + 1, e});}} else {++it;}}if (cut_segments.empty()) {cout << "0 0\n";boards[op + 1].clear();continue;}// 为了后续合并相邻区间处理,先对切割出的区间按起点排序sort(cut_segments.begin(), cut_segments.end());// 根据是否满足 c[i] = i(即 allDistinct 为 true)分别处理if (allDistinct) {// 在全不相同的情况下,每个区间内不同颜色数和颜色段数均等于区间长度int distinct_count = 0, total_segments = 0;for (auto& seg : cut_segments) {int len = seg.second - seg.first + 1;distinct_count += len;total_segments += len;}cout << distinct_count << " " << total_segments << "\n";} else {// ------------------------// 1. 利用块状分解“distinctQuery”求多个区间中不同颜色的并集// ------------------------vector<uint64_t> union_bs(W, 0ULL);// 统计所有被切区间的颜色(并集)for (auto& seg : cut_segments) {int a = seg.first, b = seg.second;vector<uint64_t> bs = distinctQuery(a, b);unionBitset(union_bs, bs);}int distinct_count = countBits(union_bs);// ------------------------// 2. 利用线段树查询每个被切区间的颜色段数,然后对相邻区间作合并处理// ------------------------int total_segments = 0;for (auto& seg : cut_segments) {int a = seg.first, b = seg.second;int seg_count, first, last;query(root, a, b, seg_count, first, last);total_segments += seg_count;}// 如果相邻两个切割区间原本是连续的且两端颜色相同,则合并后颜色段数减少1int merged = 0;for (int i = 1; i < (int)cut_segments.size(); i++) {int prev_b = cut_segments[i - 1].second;int curr_a = cut_segments[i].first;if (prev_b + 1 == curr_a) {int dummy;int col1, col2;query(root, prev_b, prev_b, dummy, col1, col1);query(root, curr_a, curr_a, dummy, col2, col2);if (col1 == col2) {merged++;}}}total_segments -= merged;cout << distinct_count << " " << total_segments << "\n";}// 新木板编号为 op+1,记录本次切下的所有区间boards[op + 1].clear();for (auto& seg : cut_segments) {boards[op + 1].insert(seg);}}return 0;
}


http://www.hkcw.cn/article/wEXyOCqPvt.shtml

相关文章

Ubuntu24.04.2 + kubectl1.33.1 + containerdv1.7.27 + calicov3.30.0

Ubuntu24.04.2 kubectl1.33.1 containerdv1.7.27 calicov3.30.0 安装Ubuntu24.04.2 kubectl1.33.1 containerdv1.7.27 calicov3.30.0 1.安装Ubuntu24.04.2&#xff0c;设置阿里云镜像地址 $ sudo vim /etc/apt/sources.list.d/ubuntu.sources URIs: https://mirrors.aliy…

Agent智能体应用教程系列(四):仅需几步,拥有自己专属的多agent智能体!

一个智能体完成多种角色任务&#xff01;今天开放猫教你用Coze&#xff08;扣子&#xff09;搭建一个可以同时输出知乎文案&#xff0c;小红书文案等多种功能的智能体搭建教程。 保证一看就会&#xff01; 以下是具体步骤&#xff1a; 创建多Agent智能体 1.1 创建智能体 1.2…

原始数据去哪找?分享15个免费官方网站

目录 一、找数据的免费官方网站 &#xff08;一&#xff09;国家级数据宝库&#xff1a;权威且全面 1.中国国家统计局 2.香港政府数据中心 3.OECD数据库 &#xff08;二&#xff09;企业情报中心&#xff1a;洞察商业本质 4.巨潮资讯 5.EDGAR数据库 6.天眼查/企查查&a…

[yolov11改进系列]基于yolov11使用图像去雾网络UnfogNet替换backbone的python源码+训练源码

【UnfogNet介绍】 UnfogNet是一种专为图像去雾设计的深度学习网络&#xff0c;旨在通过先进的算法恢复雾霾天气下图像的清晰度&#xff0c;提升视觉效果与后续计算机视觉任务的性能。其核心架构融合了编码器-解码器结构与注意力机制&#xff0c;通过多尺度特征提取与融合&…

腾讯 ovCompose 开源,Kuikly 鸿蒙和 Compose DSL 开源,腾讯的“双”鸿蒙方案发布

近日&#xff0c;腾讯的 ovCompose 和 Kuikly 都发布了全新开源更新&#xff0c;其中 Kuikly 在之前我们聊过&#xff0c;本次 Kuikly 主要是正式开源鸿蒙支持部分和 Compose DSL 的相关支持&#xff0c;而 ovCompose 是腾讯视频团队基于 Compose Multiplatform 生态推出的跨平…

SP网络结构:现代密码学的核心设计

概述 SP网络&#xff08;Substitution-Permutation Network&#xff09;是一种对称密钥密码结构&#xff0c;由Claude Shannon在1949年提出的混淆(Confusion)与扩散(Diffusion) 原则发展而来。与Feistel网络不同&#xff0c;SP网络在每轮中对整个数据块进行非线性替换和线性置…

HCIP(BGP基础)

一、BGP 基础概念 1. 网络分类与协议定位 IGP&#xff08;内部网关协议&#xff09;&#xff1a;用于自治系统&#xff08;AS&#xff09;内部路由&#xff0c;如 RIP、OSPF、EIGRP&#xff0c;关注选路效率、收敛速度和资源占用。EGP&#xff08;外部网关协议&#xff09;&a…

身份证实名认证API接口-透明网络空间-实名认证api

数字化时代&#xff0c;线上交易、社交互动、信息共享等活动已经成为人们日常生活的一部分。但随之而来的是身份盗用、欺诈等网络安全问题的不断上升。为应对这一挑战&#xff0c;身份证实名认证作为网络平台的一项基础安全功能&#xff0c;逐渐成为确保用户身份真实性、保障交…

数据安全中心是什么?如何做好数据安全管理?

目录 一、数据安全中心是什么 &#xff08;一&#xff09;数据安全中心的定义 &#xff08;二&#xff09;数据安全中心的功能 1. 数据分类分级 2. 访问控制 3. 数据加密 4. 安全审计 5. 威胁检测与响应 二、数据安全管理的重要性 三、如何借助数据安全中心做好数据安…

【Oracle】视图

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 视图基础概述1.1 视图的概念与特点1.2 视图的工作原理1.3 视图的分类 2. 简单视图2.1 创建简单视图2.1.1 基本简单视图2.1.2 带计算列的简单视图 2.2 简单视图的DML操作2.2.1 通过视图进行INSERT操作2.2.2 通…

FastMCP vs MCP:协议标准与实现框架的协同

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

消费者行为变革下开源AI智能名片与链动2+1模式S2B2C商城小程序的协同创新路径

摘要&#xff1a;在信息爆炸与消费理性化趋势下&#xff0c;消费者从被动接受转向主动筛选&#xff0c;企业营销模式面临重构挑战。本文提出开源AI智能名片与链动21模式S2B2C商城小程序的协同创新框架&#xff0c;通过AI驱动的精准触达、链动裂变机制与S2B2C生态赋能&#xff0…

Python与数据分析期末复习笔记

第一次小考自然语言处理 一、单选题&#xff08;共 29 题&#xff0c;60.0 分&#xff09; 1.(单选题&#xff0c;3.0 分) 在 matplotlib 中&#xff0c;设置 x 轴标签的方法是&#xff1f; A. title () B. xlabel () C. legend () D. ylabel () 正确答案&#xff1a;B 3.0 分 …

机电工程常用设备

一、通用设备 1. 泵 容积式泵&#xff1a; 往复泵&#xff1a;活塞泵、柱塞泵、隔膜泵&#xff08;&#xff09;。 回转泵&#xff1a;齿轮泵、螺杆泵、叶片泵&#xff08;&#xff09;。 叶轮式泵&#xff1a;离心泵、轴流泵、混流泵、旋涡泵&#xff08;按叶轮和流道结构区…

CSS设置移动端页面底部安全距离

如图&#xff1a;在开发微信小程序时遇到的按钮被iOS设备底部黑线遮挡的问题&#xff0c;以及如何利用CSS中的env(safe-area-inset-bottom)属性来创建安全区域&#xff0c;避免内容被遮挡。通过将该属性应用到padding或height上&#xff0c;成功解决了问题 env(safe-area-inset…

Go语言学习-->第一个go程序--hello world!

Go语言学习–&#xff1e;第一个go程序–hello world! 1 写代码前的准备 1 创建编写代码的文件夹 2 使用vscode打开3 项目初始化 **go mod init*&#xff08;初始化一个go mod&#xff09;Go Module 是 Go 1.11 版本引入的官方依赖管理系统&#xff0c;用于替代传统的 GOPATH…

02 C语言程序设计之导言

文章目录 1、入门1-1、引例1-2、练习题1-2-1、Job11-2-2、Job2 2、变量与算术表达式2-1、引例2-2、练习题2-2-1、Job12-2-2、Job2 3、for语句3-1、引例3-2、练习题 4、符号常量5、字符输入/输出5-1、文件复制5-1-1、引例5-1-2、练习题5-1-2-1、Job15-1-2-2、Job2 5-2、字符计数…

血管的三维重建

血管的三维重建 摘 要 断面可用于了解生物组织、器官等的形态&#xff0c;在医学上有重要的作用。用切片机连续不断地将样本切成数十、成百的平行切片&#xff0c;可依次逐片观察。根据平行切片数字图象&#xff0c;运用计算机可重建组织、器官等准确的三维形态。 本文提出了一…

如何在 DataGrip 中 连接 Databend

本文通过详细的步骤演示了如何新建 自定义 Driver 以在 DataGrip 中支持连接 Databend&#xff0c;包括设置 Class、DriverFiles 和URLtemplates。最后&#xff0c;通过新建 Driver 和 DataSource&#xff0c;并在 Databend Cloud 上进行连接测试&#xff0c;确保能成功访问数据…

黑马程序员TypeScript课程笔记2(11-20)

11.数组类型 数组类型可以写为"let numbers:number[][1,2,3] ,也可以写为let numbers:Array[1,2,3] 12.联合类型 联合类型的写法 let arr:(number|string)[][1,a,2,g] 13.类型别名(可以为任意类型起别名&#xff0c;起到一个简化类型名的作用) 14.函数类型&#xff08;1…