做题随笔:P12147
Solution
题意
定义 \(f(x)=x\oplus (x+2^k)\),给定两个整数 \(n,k\),求 \(\sum_{i = 0}^{n}f(i)\) 的值。
ps:你梦熊入门题简单又直接,令我 1h 才做完。果然,题目信息里面难度是最不能相信的。
分析
注意到有 \(30\%\) 数据满足 \(k = 0\),启发我们先考虑 \(k = 0\) 的特殊情况。
1. k = 0
一个很自然的想法是:按题目所给定义不可以直接求和,那么我们考虑一下找一个可以直接求和的表达式。场上果断暴力打表找规律。
这里是 \(k = 0,n=31\) 的数据表,请自行移步看一下。
观察数据,会发现几个很惊人的事实:
- \(x\) 为偶数时,\(f(x) = 1\);
- \(f(x)\) 不为 \(1\) 时,其取值为 \(2^k-1\);
- \(x\) 为 \(2^k-1\) 时,其取值为 \(2^{k+1}-1\);
其实到这里,一切都比较明晰了,结论就是 \(k = 0\) 时,\(f(x)=2 \times \operatorname{lowbit}(x+1)-1\)。基于梦熊标明的题目难度,说明一下 lowbit:它指一个数二进制数最低位的 \(1\) 及其对应的值.直观地说,就是一个数二进制下从右往左数第一个 \(1\) 和它右边的所有 \(0\) 共同组成的数。如 \(\operatorname{lowbit}(10)=\operatorname{lowbit}((1010)_2)=(10)_2=2\)。有 \(\operatorname{lowbit}(x)=x \operatorname{and} (-x)\)。
下面给出证明:
任意考虑一个数 \(x\),若它为偶数,它的二进制下最低位为 \(0\),加 \(1\) 后仅最后一位与原数不同,故 \(f(x)=1\),满足以上结论;若 \(x\) 为奇数,则加 \(1\) 后进位,\(x\) 将由 \((1 \dots 01 \dots 1)_2\) 的形式变成 \((1 \dots 10 \dots 00)_2\),即 \(x\) 的从右往左数第一个 \(0\) 位(设为第 \(r\) 位)及其以右的所有位都变了,故 \(x\oplus (x+2^k)\) 的结果即为 \(2^r-1=2 \times \operatorname{lowbit}(x+1)-1\)。证毕。
所以说 \(ans=\sum_{i = 0}^{n}f(i)=\sum_{i = 1}^{n+1} (2 \times \operatorname{lowbit}(i+1)-1)=2\sum_{i = 1}^{n+1} \operatorname{lowbit}(i+1)-(n+1)\)。从而问题转变为求 \(\sum_{i = 1}^{n+1} \operatorname{lowbit}(i)\)。
结合 lowbit 定义,我们可以得到 \(\sum_{i = 1}^{x} \operatorname{lowbit}(i)\) 的一个递推式(设 \(\sum_{i = 1}^{x} \operatorname{lowbit}(i)=g(x)\)):
\(g(x) = \begin{cases} \frac{n}{2}+2g(\frac{n}{2}) & x \in even\\ \frac{n+1}{2}+2g(\frac{n-1}{2}) & x \in odd\\ \end{cases}\)
为什么呢?对偶数情况进行一下说明:\([1,n]\) 中有奇数、偶数各 \(\frac{n}{2}\) 个,奇数的 lowbit 定为 \(1\);然后将所有数除以二进行同样的考虑即得。奇数同理。边界是 \(g(0)=0,g(1)=1\)。
于是 \(k=0\) 的问题可以在 \(O(Tlogn)\) 的时间复杂度下解决。
2. k ≠ 0
同样先给出数据。
定义 \(h(x,y)\) 为 \(f(x)\) 在 \(k=y\) 时的值,有 \(h(x,k)=2^kf([\frac{x}{2^k}],0)\),其中,\([x]\) 表示不大于 \(x\) 的最大整数。这里直接给出直观证明:\(x\) 加上 \(2^k\) 后,对低于 \(2^k\) 的位没有任何影响,且那些位的值也不会影响 \(x\oplus (x+2^k)\) 的值,故可以直接舍去。相当于 \(x\) 每增加 \(2^k\) 才等价于 \(k=0\) 时增加 \(1\),体现在式子上就是 \([\frac{x}{2^k}]\) 项。但是对比 \(k=0\) 时,变化的最低位为 \(2^k\) 位,故再乘上一个 \(2^k\)。
于是 \(n\) 相当于 \(k=0\) 时完整的 \(1\) 到 \([\frac{x}{2^k}]\) 与剩下一部分 \([\frac{x}{2^k}]+1\)。由上亦得 \(h(x,y)\) 中连续的 \(2^k\) 项是相同的,故完整的数乘上 \(2^k\),不完整的单独计算,得:
\(ans(k)=2^k[2(2^kans_0(s)+r \operatorname{lowbit} (s+1))-(n+1)]\),
其中 \(ans_0(x)\) 为 \(n = x,k=0\) 时的答案,\(s=\frac{n+1}{2^k},r=(n+1) \bmod 2^k\)。
于是问题在 \(O(Tlogn)\) 的时间复杂度下解决。
感觉分析得已经比较详细了,代码没写注释,将就看下吧。
实现
- lowbit 函数(不要宏定义,本蒟蒻因此改了至少二十分钟);
- lowbit 的求和递归式;
- 直接计算输出。
Code
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
typedef long long ll;
ll fr() {
ll x=0,f=1;
char c=getchar();
while(!isdigit(c)) {
if(c=='-') f=-1;
c=getchar();
}
while(isdigit(c)) {
x=(x<<3)+(x<<1)+(c^48);
c=getchar();
}
return x*f;
}
ll t,n,k,ans;
inline ll lowbit(ll x) {return x&(-x);}
ll gets(int x) {
if(x<=1) return x;
return ((x&1)?((x+1)>>1):(x>>1))+(gets(x>>1)<<1);
}
int main() {
t=fr();
while(t--) {
ans=0;n=fr(),k=fr();
ll s=(n+1)/(1<<k),r=(n+1)%(1<<k);
printf("%lld\n",(1<<k)*(2*((1<<k)*gets(s)+r*lowbit(s+1))-n-1));
}
return 0;
}
闲话
如果觉得有用,点个赞吧!