做题随笔: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\) 的数据表,请自行移步看一下。

观察数据,会发现几个很惊人的事实:

  1. \(x\) 为偶数时,\(f(x) = 1\)
  2. \(f(x)\) 不为 \(1\) 时,其取值为 \(2^k-1\)
  3. \(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)\) 的时间复杂度下解决。

感觉分析得已经比较详细了,代码没写注释,将就看下吧。

实现

  1. lowbit 函数(不要宏定义,本蒟蒻因此改了至少二十分钟);
  2. lowbit 的求和递归式;
  3. 直接计算输出。

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;
}

闲话

如果觉得有用,点个赞吧!

posted @ 2025-04-12 18:07  Tenil  阅读(23)  评论(0)    收藏  举报