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

 原题链接:

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.pswp.cn/diannao/85674.shtml

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

相关文章

【蓝桥杯】包子凑数

包子凑数 题目描述 小明几乎每天早晨都会在一家包子铺吃早餐。他发现这家包子铺有 NN 种蒸笼&#xff0c;其中第 ii 种蒸笼恰好能放 AiAi​ 个包子。每种蒸笼都有非常多笼&#xff0c;可以认为是无限笼。 每当有顾客想买 XX 个包子&#xff0c;卖包子的大叔就会迅速选出若干…

pikachu通关教程-目录遍历漏洞(../../)

目录遍历漏洞也可以叫做信息泄露漏洞、非授权文件包含漏洞等. 原理:目录遍历漏洞的原理比较简单&#xff0c;就是程序在实现上没有充分过滤用户输入的../之类的目录跳转符&#xff0c;导致恶意用户可以通过提交目录跳转来遍历服务器上的任意文件。 这里的目录跳转符可以是../…

[概率论基本概念4]什么是无偏估计

关键词&#xff1a;Unbiased Estimation 一、说明 对于无偏和有偏估计&#xff0c;需要了解其叙事背景&#xff0c;是指整体和抽样的关系&#xff0c;也就是说整体的叙事是从理论角度的&#xff0c;而估计器原理是从实践角度说事&#xff1b;为了表明概率理论&#xff08;不可…

面试题——计算机网络:HTTP和HTTPS的区别?

HTTP&#xff08;HyperText Transfer Protocol&#xff09;&#xff1a;作为互联网上应用最广泛的网络通信协议&#xff0c;HTTP是基于TCP/IP协议族的应用层协议。它采用标准的请求-响应模式进行通信&#xff0c;通过简洁的报文格式&#xff08;包含请求行、请求头、请求体等&a…

uni-app学习笔记十九--pages.json全局样式globalStyle设置

pages.json 页面路由 pages.json 文件用来对 uni-app 进行全局配置&#xff0c;决定页面文件的路径、窗口样式、原生的导航栏、底部的原生tabbar 等。 导航栏高度为 44px (不含状态栏)&#xff0c;tabBar 高度为 50px (不含安全区)。 它类似微信小程序中app.json的页面管理部…

SQL思路解析:窗口滑动的应用

目录 &#x1f3af; 问题目标 第一步&#xff1a;从数据中我们能直接得到什么&#xff1f; 第二步&#xff1a;我们想要的“7天窗口”长什么样&#xff1f; 第三步&#xff1a;SQL 怎么表达“某一天的前六天”&#xff1f; &#x1f50d;JOIN 比窗口函数更灵活 第四步&am…

解决MyBatis参数绑定中参数名不一致导致的错误问题

前言 作为一名Java开发者&#xff0c;我在实际项目中曾多次遇到MyBatis参数绑定的问题。其中最常见的一种情况是&#xff1a;在Mapper接口中定义的参数名与XML映射文件中的占位符名称不一致&#xff0c;导致运行时抛出Parameter xxx not found类异常。这类问题看似简单&#x…

黑马程序员TypeScript课程笔记—类型兼容性篇

类型兼容性的说明 因为传入的时候只有一个参数 对象之间的类型兼容性 接口之间的类型兼容性 函数之间的类型兼容性&#xff08;函数参数个数&#xff09; 和对象的兼容性正好相反 函数之间的类型兼容性&#xff08;函数参数类型&#xff09; 函数参数的兼容性就不要从接口角度…

智能电视的操作系统可能具备哪些优势

丰富的应用资源&#xff1a; 操作系统内置了应用商店&#xff0c;提供了丰富的应用资源&#xff0c;涵盖视频、游戏、教育等多个领域&#xff0c;满足不同用户的多样化需求。用户可以轻松下载并安装所需的应用&#xff0c;享受更多元化的娱乐和学习体验。 流畅的操作体验&…

Xget 正式发布:您的高性能、安全下载加速工具!

您可以通过 star 我固定的 GitHub 存储库来支持我&#xff0c;谢谢&#xff01;以下是我的一些 GitHub 存储库&#xff0c;很有可能对您有用&#xff1a; tzst Xget Prompt Library 原文 URL&#xff1a;https://blog.xi-xu.me/2025/06/02/xget-launch-high-performance-sec…

精美的软件下载页面HTML源码:现代UI与动画效果的完美结合

精美的软件下载页面HTML源码&#xff1a;现代UI与动画效果的完美结合 在数字化产品推广中&#xff0c;一个设计精良的下载页面不仅能提升品牌专业度&#xff0c;还能显著提高用户转化率。本文介绍的精美软件下载页面HTML源码&#xff0c;通过现代化UI设计与丰富的动画效果&…

麒麟v10+信创x86处理器离线搭建k8s集群完整过程

前言 最近为某客户搭建内网的信创环境下的x8s集群&#xff0c;走了一些弯路&#xff0c;客户提供的环境完全与互联网分离&#xff0c;通过yum、apt这些直接拉依赖就别想了&#xff0c;用的操作系统和cpu都是国产版本&#xff0c;好在仍然是x86的&#xff0c;不是其他架构&…

Pycharm的使用技巧总结

目录 一、高效便捷的快捷键 二、界面汉化处理 1.设置 2.插件 3.汉化插件安装 三、修改字体大小、颜色 1.选择文件-设置 2.选择编辑器-配色方案-python 3.修改注释行颜色 4.修改编辑器字体颜色 一、高效便捷的快捷键 序号快捷键功能场景效果1Ctrl /快速注释/取消注释…

安全编码规范与标准:对比与分析及应用案例

在软件开发领域&#xff0c;尤其是涉及安全关键系统的开发中&#xff0c;遵循编码规范和标准是确保软件质量和安全性的重要手段。除了CERT C、CERT Java和MISRA外&#xff0c;还有其他多个与安全相关的编码规范和标准&#xff0c;以下是一些主要标准的对比说明&#xff1a; 一…

FFmpeg学习笔记

1. 播放器的架构 2. 播放器的渲染流程 3. ffmpeg下载与安装 3.0 查看PC是否已经安装了ffmpeg ffmpeg 3.1 下载 wget https://ffmpeg.org/releases/ffmpeg-7.0.tar.gz 3.2 解压 tar zxvf ffmpeg-7.0.tar.gz && cd ./ffmpeg-7.0 3.3 查看配置文件 ./configure …

大宽带怎么做

我有10个G的宽带资源&#xff0c;怎样运行P2P才能将收益巨大化&#xff0c;主要有以下几种方式&#xff1a; 1.多设备汇聚模式&#xff1a;使用多台支持千兆网络的服务器或专用PCDN设备&#xff08;如N1盒子&#xff09;&#xff0c;将10条宽带分别接入不同设备&#xff0c;通过…

pytorch基本运算-导数和f-string

引言 在前序对机器学习的探究过程中&#xff0c;我们已经深刻体会到人工智能到处都有微分求导运算&#xff0c;相关文章链接包括且不限于&#xff1a; BP神经网络 逻辑回归 对于pytorch张量&#xff0c;求导运算必不可少&#xff0c;所以本次就专门来学习一下。 f-string的用…

dvwa4——File Inclusion

LOW: 先随便点开一个文件&#xff0c;可以观察到url栏变成这样&#xff0c;说明?page是dvwa当前关卡用来加载文件的参数 http://10.24.8.35/DVWA/vulnerabilities/fi/?pagefile1.php 我们查看源码 &#xff0c;没有什么过滤&#xff0c;直接尝试访问其他文件 在url栏的pag…

经典面试题:一文了解常见的缓存问题

在面试过程中&#xff0c;面试官的桌子上摆放着很多高频的面试题&#xff0c;能否顺利回答决定了你面试通过的概率。其中缓存问题就是其中的一份&#xff0c;可以说掌握缓存问题及解决方法是面试前必须准备的内容。那么缓存有什么典型的问题&#xff0c;出现的原因是什么&#…

生产环境中安装和配置 Nginx 以部署 Flask 应用的详细指南

在生产环境中部署 Flask 应用时&#xff0c;Nginx 常被用作反向代理服务器&#xff0c;与 WSGI 服务器&#xff08;如 Gunicorn&#xff09;协同工作。Nginx 可以处理静态文件、提供 SSL/TLS 加密、实现负载均衡等功能。本文将详细介绍如何在 Ubuntu/Debian 系统上安装 Nginx&a…