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

chen_zhe
Aya 敲可爱的~搬运于
2025-08-24 22:39:04,当前版本为作者最后更新于2022-07-18 13:13:19,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
cz 过了,用的是点名被卡但是卡卡常就能冲过去的写法。
本题的最大难点在于,对洛谷评测机的效率的高度了解。
首先,不难根据题目中对于 的定义,暴力地计算出最后的结果。因为答案是对 取模,因而可以直接采用
unsigned long long进行全程的运算,直接自然溢出啥事没有。如果你手写去拆二进制速度是慢的。这里可以使用内建函数
__builtin_ffs(x),返回 中最后一个为 的位是从后向前的第几位。可以将拆二进制位的一个 的复杂度去掉。参考代码如下:
for (int i=1;i<(1<<n);i++) { for (int j=__builtin_ffs(i);j;j--) ret^=a[j]; ans^=ret*i; }如果你提交这个代码,你会发现在 的情况下跑了 79ms。而当 的情况下应该要多跑 倍的时间,也就是 2.5s。
我们考虑对这个循环进行一定的优化。我们考虑对于相邻 个正整数的二进制串,那么它们的末尾将会是如下的循环:、、、。
而对于 、、 的部分我们可以只需要分别让
ret异或上a[1]、a[1] xor a[2]、a[1]即可。对于 的部分,再暴力跑for (int j=__builtin_ffs(i);j;j--)这层循环。可以让调用__builtin_ffs()函数的次数变成原来的 ,而且也减少了新定义变量的次数。此外,将对
ret和ans两个变量的计算进行了上述的展开,本质也会加速 CPU 的流水线调度,进一步地去优化常数。这样,你的代码就足以通过此题了。实际上这样做的常数是相当优秀的(循环展开相当于除以 ,对__builtin_ffs()循环的优化也大幅度减小了常数,而且本身这个循环就很难跑到 次的)。如果你实测一下的话会发现,内层循环跑了恰好 次,因而可以通过本题。代码如下:
int n; unsigned long long a[33],ret=0,ans; int main() { n=read(); for (int i=1;i<=n;i++) a[i]=read(); int i; for (i=1;i+4<(1<<n);) { ret^=a[1]; ans^=ret*(i++); ret^=a[1]^a[2]; ans^=ret*(i++); ret^=a[1]; ans^=ret*(i++); for (int j=__builtin_ffs(i);j;j--) ret^=a[j]; ans^=ret*(i++); } ret^=a[1]; ans^=ret*(i++); ret^=a[1]^a[2]; ans^=ret*(i++); ret^=a[1]; ans^=ret*(i++); cout << ans << endl; return 0; }实际上,洛谷评测机的速度是足以支持在 1 秒内进行 次
unsigned long long类型变量相乘并且自然溢出的。所以如果是小常数 , 是能跑的。这里就需要指出另外一种做法:将高低位拆分之后暴力合并去计算。这样的做法的时间复杂度也是很高的,因为它要将两个 大小的数组去合并运算。但是实际上跑的是非常非常快的。
for(i=0;i<lim1;i++) { for(j=0;j<lim2;j++) ans^=(dp[i]^dp2[j])*(unsigned long long)(i+j*lim1); }实际上我们可以使用如下代码获得洛谷评测机的 CPU 型号:
#include <stdint.h> #include <iostream> #include <cpuid.h> static void cpuid(uint32_t func, uint32_t sub, uint32_t data[4]) { __cpuid_count(func, sub, data[0], data[1], data[2], data[3]); } int main() { uint32_t data[4]; char str[48]; for(int i = 0; i < 3; ++i) { cpuid(0x80000002 + i, 0, data); for(int j = 0; j < 4; ++j) reinterpret_cast<uint32_t*>(str)[i * 4 + j] = data[j]; } std::cout << str; }可得洛谷 CPU 型号为
Intel(R) Xeon(R) Platinum 8369HC CPU @ 3.30GHz。然而由于这个是阿里云定制 CPU,其实很难查到它的参数数据。但是与其同一代的 CPU
Intel(R) Xeon(R) Platinum 8360HC CPU @ 3.00GHz的 Cache 大小是 33MB,而有着 24 个核心,也就是说每个核心有着 1.375MB 的高速缓存,足以存下两个大小为 65536 的 unsigned long long 数组。当这些数组进入高速缓存(实际上应该是 L3 cache)之后,其读写效率是显著快于在内存中的读写的(快 4 倍左右)。此外,合并的过程做的都是连续的内存访问,有着很好的空间局部性,也减少了常数。因而,它在 的复杂度下能够跑的很快。
- 1
信息
- ID
- 7433
- 时间
- 1400ms
- 内存
- 8~256MiB
- 难度
- 3
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者