思路:第一次先把往后距离为 $k$ 的点算出来,然后再每次往前走一个,考虑 $k-i$ 的情况。(具体见代码注释)。
代码:
```cpp
#include <bits/stdc++.h>
using namespace std;
// head
int sum[100],head=0;
int n,x,k;
int ans;
void f(int now,int step) //从点 now 开始,往上距离 step 的点的个数
{
int cnt=0;
while(cnt<step){ //找到距离 step 的层数
if(now*2>n) break;
cnt++;
now*=2;
}
if(cnt>=step){ //判断距离是否合格
ans+=sum[cnt]; //相加
if(now+sum[cnt]-1>n) ans=ans-(now+sum[cnt]-1-n);
//因为有可能这一排并不全(缺几个点),所以要减掉。
}
}
signed main()
{
cin.tie(nullptr);
ios::sync_with_stdio(false);
int tmp=1;
while(tmp<1e18){
sum[head++]=tmp;
tmp*=2;
}
int q;cin>>q;
while(q--)
{
cin>>n>>x>>k;
if(k==0){cout<<"1"<<endl;continue;} //0特殊
ans=0;
if(x==1){ //1特殊,你也可以不特拎出来
f(x*2,k-1);
f(x*2+1,k-1);
cout<<ans<<endl;
continue;
}
f(x,k); //先以改点往上找一次
tmp=x;
int cnt=k-1;
while(tmp!=1&&cnt>=0){
if(cnt==0) {ans++;break;}
int tmp1=tmp;
tmp/=2;
cnt--;
if(tmp*2==tmp1) f(tmp*2+1,cnt); //判断左右子树
else f(tmp*2,cnt);
}
cout<<ans<<endl;
}
}
```
蒟蒻本人账号,~~可以去点个关注~~:[https://atcoder.jp/users/gangbengr]