6-1. Code For 1

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 1 &lt; = 2 , 3 &lt; 2 2 2^1&lt;=2,3&lt;2^2 21<=2,3<22,所以2,3最后分成的长度为 2 0 + 2 1 = 3 2^0+2^1=3 20+21=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]
因为 2 2 = &lt; 4 , 5 , 6 , 7 &lt; 2 3 2^2=&lt;4,5,6,7&lt;2^3 22=<4,5,6,7<23,所以4,5,6,7最后分成的长度为 2 0 + 2 1 + 2 2 = 7 2^0+2^1+2^2=7 20+21+22=7
8->[0,1,0]->[4,0,4]->[1,0,1,0,1,0,1,0,1,0,1,0,1,0,1]
所以我们发现了规律,当 2 n &lt; = x &lt; 2 n + 1 2^n&lt;=x&lt;2^{n+1} 2n<=x<2n+1时,最终的长度为 2 0 + 2 1 + 2 2 + . . . + 2 n = 2 n + 1 − 1 2^0+2^1+2^2+...+2^n=2^{n+1}-1 20+21+22+...+2n=2n+11
下面我们就可以通过二分来做题了。

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值