蓝桥杯刷题日记day2

小蓝发现了一个有趣的数列,这个数列的前几项如下:
1, 1, 2, 1, 2, 3, 1, 2, 3, 4, …
小蓝发现,这个数列前 1 项是整数 1,接下来 2 项是整数 1 至 2,接下来3 项是整数 1 至 3,接下来 4 项是整数 1 至 4,依次类推。
小蓝想知道,这个数列中,连续一段的和是多少?

输入格式
输入的第一行包含一个整数 T,表示询问的个数。
接下来 T 行,每行包含一组询问,其中第 i 行包含两个整数 li 和 ri,表示询问数列中第 li 个数到第 ri 个数的和。


输出格式
输出 T 行,每行包含一个整数表示对应询问的答案。


样例输入
3
1 1
1 3
5 8
样例输出
1
4
8

评测用例规模与约定
对于 10% 的评测用例, 1 ≤ T ≤ 30, 1 ≤ li ≤ ri ≤ 100。
对于 20% 的评测用例, 1 ≤ T ≤ 100, 1 ≤ li ≤ ri ≤ 1000。
对于 40% 的评测用例, 1 ≤ T ≤ 1000, 1 ≤ li ≤ ri ≤ 10 ^ 6。
对于 70% 的评测用例, 1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 10 ^ 9。
对于 80% 的评测用例, 1 ≤ T ≤ 1000, 1 ≤ li ≤ ri ≤ 10 ^ 12。
对于 90% 的评测用例, 1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 10 ^ 12。
对于所有评测用例, 1 ≤ T ≤ 100000, 1 ≤ li ≤ ri ≤ 10 ^ 12。

题解:

利用二分的思想(但是这个二分的上界MAX不知道怎么确定,我是加0减0试出来的,太大了会越界)先查找到li所在的区间,再在li的基础上暴力找到ri的区间(能不能再用一次二分找到ri的区间呢,可以一试),过了80%的测试用例,剩余20%超时,时间复杂度还有待优化。(5.11版本v1.0,希望有生之年能优化它)

#include <stdio.h>
#include <stdlib.h>
#define MAX 10000000			//试出来的,太大会越界

long long leijia(long long x, long long y)
{
  long long a = y-x+1;
  if(a%2==0)  //a是偶数
  {
    return (x+y)*(a/2);
  }
  else        //a是奇数
  {
    return (x+y)*(a/2)+((x+y)/2);     //修改2:a/2-1改成(x+y)/2
  }
}

long long binary_search(long long x, long long y)
{
  long long low = 1;
  long long high = MAX;
  while(low <= high)
  {
    long long mid = (low+high)/2;
    long long left = leijia(1,mid-1);
    long long right = leijia(1,mid);
    if(x > left && x <= right)
    {
      //x所在区间的大小为mid,还需判断y是和x在同一个区间,还是在其后的某个区间
      long long num = y-x+1;                //从x到y的元素个数
      long long num1 = mid-(x-left)+1;      //从x到区间mid末尾的元素个数
      if(num <= num1)     //y和x在同一个区间
      {
        return leijia(x-left,y-left);
      }
      else                //y在mid其后的某个区间
      {
        long long sum=0;
        long long i=1;
        num -= num1;
        sum += leijia(x-left,mid);
        while(num-(mid+i)>=0)       //判断y是否在mid+i区间内
        {
          sum += leijia(1,mid+i);
          num -= mid+i;       //修改1:1改成了i
          i++;
        }
        sum += leijia(1,num);
        return sum;
      }
    }
    else if(x <= left)
    {
      high = mid-1;
    }
    else
    {
      low = mid+1;
    }
  }
}

int main(int argc, char *argv[])
{
  int t;
  scanf("%d",&t);
  long long a[t][2];
  long long res[t];
  int i;
  for(i=0;i<t;i++)
  {
    scanf("%lld %lld",&a[i][0],&a[i][1]);
  }
  for(i=0;i<t;i++)
  {
    res[i] = binary_search(a[i][0],a[i][1]);
  }
  for(i=0;i<t;i++)
  {
    printf("%lld\n",res[i]);
  }
  return 0;
}


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值