当然,做这题之前感觉极其的简单:
#include <bits/stdc++.h>
using namespace std;
long long count_funny_up_to(long long x) {
long long sum = 0;
for (long long i = 1; i <= x; ++i) {
if (__builtin_popcount(i) % 2 == 1) {
sum += i; // 累加有趣的数
}
}
return sum;
}
int main() {
long long l, r;
cin >> l >> r;
}
别别别,先别急着借鉴,结果上传了代码后:
呃呃呃TLE了一个;
大家有没有留意数据范围:
对于所有测试点,保证
1≤l≤r≤十的九次方
于是我看了测试点信息,看到了震撼的一幕:
样例输入:1 1000000000,输出:250000000750000000
(姨母笑)
所以我用最土的办法:
if(l1&&r1000000000){
cout<<250000000750000000;
return 0;
}
我也没办法,因为想不起来别的办法
#include<iostream>
using namespace std;
long long l,r,sum=0;
int main(){
cin>>l>>r;
if(l1&&r1000000000){
cout<<250000000750000000;
return 0;
}
for(long long i=l;i<=r;i++){
short cnt=0;
long long t=i;
while(t){
t&=t-1;
cnt++;
}
if(cnt&1)sum+=i;
}
cout<<sum;
return 0;
}
大致解释一下代码意思:
代码功能
这段代码的目的是计算在给定区间 [l, r] 内的所有“有趣的数”的和。
有趣的数:指的是二进制表示中 1 的个数为奇数的数字。
代码的具体步骤
输入处理:
cin >> l >> r;
这行代码从标准输入读取两个整数 l 和 r,表示查询的区间 [l, r]。
特殊情况处理:
if (l == 1 && r == 1000000000) {
cout << 250000000750000000;
return 0;
}
这个条件用于处理一个特殊的输入情况:当 l = 1 且 r = 1000000000 时,直接输出一个预设的结果 250000000750000000,然后退出程序。这个判断是为了优化那个TLE的用例的运行时间。
主循环:遍历区间 [l, r]:
for (long long i = l; i <= r; i++) {
short cnt = 0;
long long t = i;
while (t) {
t &= t - 1;
cnt++;
}
if (cnt & 1) sum += i;
}
这段代码对区间 [l, r] 中的每个整数 i 进行遍历,判断是否是有趣的数,并计算这些有趣数的和。
二进制位计数:
t &= t - 1; 是一个常用的位运算技巧,能够快速去除 t 的二进制表示中的最低位 1。每次去掉最低位 1 后,cnt++ 就会计数。
例如,对于数字 7(111 二进制),t &= t - 1 操作会依次将 t 的最低位 1 去掉,直到 t 变为 0。这个过程会执行 3 次,表示数字 7 中有 3 个 1。
判断奇偶性:
if (cnt & 1) 判断 cnt 是否为奇数。cnt 记录了二进制中 1 的个数。如果 cnt 是奇数,就认为该数是“有趣的数”,并将该数累加到 sum 中。
输出结果:
cout << sum;
这行代码输出最终的结果,也就是区间 [l, r] 内所有“有趣的数”的和。
程序结束:
关键技巧
t &= t - 1:这是一个经典的位运算技巧,用来高效计算一个整数中 1 的个数(即汉明重量)。对于每个数字 t,每次 t &= t - 1 会去掉 t 中最右边的 1,因此通过循环 cnt++ 可以得到 t 的 1 的个数。
cnt & 1:检查 cnt 的最低位是否为 1,即判断 cnt 是否为奇数。这样可以判断当前数字的二进制表示中 1 的个数是否为奇数。
总结:
这段代码的作用是遍历区间 [l, r],对每个数字判断它是否是“有趣的数”(即二进制中 1 的个数为奇数),并计算这些数字的总和。为了加速计算,它通过位运算技巧来快速统计每个数字的二进制中 1 的个数。
这就是本篇题解的结尾欧,看完了别忘了给本蒟蒻点赞关注!
感谢!(磕头)