Code For 1 题解

· · 题解

前言

古诗学习:

一头犁牛半块田,收也凭天,荒也凭天。

粗茶淡饭饱三餐,早也香甜,晚也香甜。

布衣得暖胜丝绵,长也可穿,短也可穿。

草屋茅舍有几间,行也安然,睡也安然。

雨过天晴驾小船,鱼在一边,酒在一边。

日上三竿犹在眠,不是神仙,胜是神仙。

省流:纯数学推公式

复杂度 O( \log n)

引理

本题要求我们拆出 \lfloor\frac{n}{2}\rfloor,n\bmod 2,\lfloor\frac{n}{2}\rfloor 三个数,因为 \lfloor\frac{n}{2}\rfloor=\lfloor\frac{n}{2}\rfloor 所以我们不难看出本题生成的答案树具有对称性,所以兄弟节点的答案相同。因此我们可以吧这个二叉树压缩为一个链,把 n\bmod 2 装入链中。

图例

我们用 n=7 举例

  1. 我们先画出 n=7 所生成的二叉树

  1. 然后把它压缩为一个链进行存储

  1. 我们把 a_1a_2 挪到 a_3

这时我们很容易看出 [l,r] 内的 1 的数量要分层讨论,因为不同层数的模数并不相同。所以分层讨论是有必要的。

位置分析

由于 l,r 与当层节点的相对位置会对答案有影响,故接下来对它们的位置关系进行逆天分析。

引理

## 位置处理如下 由于只需要考虑 $r$ 与 $l$ 右侧第一个节点(若 $l$ 与当层某个节点重合,则 $l$ 也需取到)的相对位置,故可视作当层 $l$ 右侧第一个节点左侧全部被删除。 现已知需要**整体左移**一部分,那么需要**左移**多少呢? 首先,当层左端第一个节点的左侧会存在一些空槽位(若为最底层则没有),通过观察我们不难看出,这些空槽位的数目与层数是有一定关系的。假设最下层的层数是 $1$,总层数是 $cnt$,由下往上正在处理第 $i$ 层,则当层前置空槽位的数目为 $2^{i-1}-1$,所以我们先把这部分删去,即整体左移 $2^{i-1}-1$ 个槽位。 然后此时当层就是以一个节点为开头的了,那么 $l$ 左侧会有整数个循环区间,那么当层的循环区间长度为 $2^i$,那么左移长度是不是就等于 $$ \lceil \frac{l-2^{i-1}+1}{2^i} \rceil \times 2^i $$ 错!!! 如果此时 $l$ 刚好与当层某一个节点**重合**的话,它向上取整后则会**多删去一个区间**,所以我们做一点小调整: 把 $l-1$ 之后再去做这个算式是不是就正确了? 所以这个时候左移的**总位数**即是 $$ \lceil \frac{l-2^{i-1}}{2^i} \rceil \times 2^i+2^{i-1}-1 $$ 所以更新后的**区间长度**即为 $$ r-\lceil \frac{l-2^{i-1}}{2^i} \rceil \times 2^i-2^{i-1}+1 $$ 那这个时候如果你已经完全理解上述意思的话,我们是不是就可以看这个区间里有多少个循环区间?(注意:不完全取到的区间也要算上,因为只算区间头部的那一个节点,所以我们**向上取整**) 所以我们的最终答案为 $$ ans=\sum^{cnt}_{i=1}{ \lceil \frac{r-\lceil \frac{l-2^{i-1}}{2^i} \rceil \times 2^i-2^{i-1}+1}{2^i} \rceil \times a_{cnt-i+1}} $$ (由于 $a$ 数组是**自上而下**存储的,所以求和的时候应该是 $a_{cnt-i+1}$) ## 最后附上 AC 代码 ```cpp #include<bits/stdc++.h> using namespace std; #define int long long int n,l,r,a[105],cnt; signed main() { cin>>n>>l>>r; while(n) { a[++cnt]=n%2; n/=2; } int ans=0; int d=1; for(int i=cnt;i>=1;i--) { d*=2; int a1=ceil(double((l-d/2)*1.0/d))*d; int a2=ceil(double((r-d/2+1-a1)*1.0/d)); ans+=a2*a[i]; } cout<<ans; return 0; } ``` 完结撒花!!!