6.1
题目大意:
给一个数n,和一个区间[l,r] (r-l<1e5,n<2^50),每次需要把序列中大于1的数字分成(n/2,n%2,n/2)(其中n/2是向下取整),直到所有数变成0或1,问[l,r]区间内有多少个1。
注意一点:l和r都是大于1的,所以我们的下标是[l-1,r-1]。
之前我做这道题目的时候用的方法是直接模拟,发现能过matrix但是过不了cf,于是我在网上搜索了一下,发现这道题目考的知识点其实是二分。
我们先来看几个例子:
1->[1]
2->[1,0,1]
3->[1,1,1]
因为
,所以2,3最后分成的长度为
4->[2,0,2]->[1,0,1,0,1,0,1]
5->[0,1,0]->[1,0,1,1,1,0,1]
6->[0,1,0]->[1,1,1,0,1,1,1]
7->[0,1,0]->[1,1,1,1,1,1,1]
因为
,所以4,5,6,7最后分成的长度为
8->[0,1,0]->[4,0,4]->[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1]
所以我们发现了规律,当
时,最终的长度为
下面我们就可以通过二分来做题了。
#include<iostream>
#include<vector>
using namespace std;
using ll=long long;
ll len=1;
ll n,l,r,ans;
void dfs(ll a,ll b,ll l,ll r,ll n)//a,b表示查找区间的范围,l,r表示需要的计算的范围。
{
if(a>b||l>r)
return;
ll mid=(a+b)/2;
if(l>mid)//全在右边
dfs(mid+1,b,l,r,n/2);
else if(r<mid)//全在左边
dfs(a,mid-1,l,r,n/2);
else//mid在l和r的中间
{
ans+=n%2;
dfs(a,mid-1,l,mid-1,n/2);
dfs(mid+1,b,mid+1,r,n/2);
}
}
int main()
{
cin>>n>>l>>r;
//求长度;
ll temp=n;
while(temp>=2)
{
len=len*2+1;
temp/=2;
}
dfs(1,len,l, r,n);
cout<<ans<<endl;
}