1 条题解
-
0
自动搬运
来自洛谷,原作者为

kimidonatsu
再见 OI搬运于
2025-08-24 21:14:15,当前版本为作者最后更新于2022-11-02 20:03:35,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
B3665 题解
题意简述
其实说起来也很简单,就是给
n条数据和q次询问,需要存储下数据以备询问,最后在查询时将答案统计在ans里(使用按位异或和,即^)。题目分析
这道题的考点在于数据的存储,很多同学可能和我一样,写了一份二维数组的代码,但是交上去却爆了个 0。
那么我们可以来到数据规模部分,我们不难发现,题目给的数据是很大的,需要使用
unsigned long long,但是用它开数组一定会爆空间,也就是俗称的MLE。那么有什么办法呢?在 C++ 的 STL 中有一个序列式容器,称为
vector。那么什么是vector呢?std::vector是 STL 提供的 内存连续的、可变长度 的数组(亦称列表)数据结构。能够提供线性复杂度的插入和删除,以及常数复杂度的随机访问。 —— OI WIKI我们知道我们很有很多时候不能提前开好足够大空间的长数组(e.g. 就像本题),就算控制下来了,单份数据可能还是会非常大(e.g. 还是本题)。那么这个时候,我们就可以使用
vector来把内存控制在空间范围下。而且vector还支持 动态扩容 ,在内存紧张的时候就可以派上用场了(e.g. 仍然是本题……)在这道题我们还会运用到在 C++11 中支持的
vector列表初始化(详见 cppreference)。vector使用方法在这里先讲一些基础的用法:
-
push_back()成员函数在vector的末尾插入值,如果有必要会扩展vector的大小。 -
size()函数显示vector的大小。 -
begin()函数返回一个指向vector开头的迭代器。 -
end()函数返回一个指向vector末尾的迭代器。
那么我们就可以愉快地写出代码了~
代码
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ull; const ull N = 4e6; ull n, q, s, x, y, ans; vector<ull> a[N]; int main() { scanf("%llu %llu", &n, &q); /* 存储数据 */ for (ull i = 1; i <= n; i++) { scanf("%llu", &s); for (ull j = 1; j <= s; j++) { ull tmp; scanf("%llu", &tmp); a[i].push_back(tmp); } } /* 处理询问 */ for (ull i = 1; i <= q; i++) { scanf("%llu %llu", &x, &y); ans ^= a[x][y - 1]; } printf("%llu\n", ans); return 0; }代码小注:
-
此处的
typedef是用于自定义变量类型名的,由于unsigned long long实在是又臭又长,所以使用typedef将它定义为ull方便使用。 -
使用
const定义数组的原因是在 C++ 中const 常量有数据类型,编译器可以对它进行类型安全检查,开到了 是防一手数据太大。 -
这里的
vector<ull> a[N]的写法正是前文提及的vector所支持的 列表初始化,包括在下文中使用到的直接使用[]运算符直接操作vector,也正是应用到了这个特性。 -
在
for循环中定义tmp是因为在for中的变量在跳循环之后会回卷删除,所以能节省一部分空间。 -
在计算答案时使用的是
a[x][y - 1],这是因为vector的数组和正常数组一样,也是从下标0开始。
结语
需要注意的是,
vector的底层实现还是定义长数组,能够实现动态扩容的原因是因为添加了防溢出的操作。所以如果可以善用resize()和reverse(),就可以使得vector的复杂度与普通数组差不多。引用资料
各位有兴趣的同学可以自己探索:
-
- 1
信息
- ID
- 8076
- 时间
- 2000ms
- 内存
- 512MiB
- 难度
- 2
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者