2021年蓝桥杯C/C++B组F题-123

目录

2021年蓝桥杯C/C++B组F题-123

题目 2618: 蓝桥杯2021年第十二届国赛真题-123

解题思路:


2021年蓝桥杯C/C++B组F题-123

题目链接:蓝桥杯2021年第十二届国赛真题-123 - C语言网

题目 2618: 蓝桥杯2021年第十二届国赛真题-123

时间限制: 1Sec 内存限制: 128MB 提交: 1302 解决: 167

题目描述

小蓝发现了一个有趣的数列,这个数列的前几项如下:
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 ≤ 106。
对于 70% 的评测用例,1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 109。
对于 80% 的评测用例,1 ≤ T ≤ 1000, 1 ≤ li ≤ ri ≤ 1012。
对于 90% 的评测用例,1 ≤ T ≤ 10000, 1 ≤ li ≤ ri ≤ 1012。
对于所有评测用例,1 ≤ T ≤ 100000, 1 ≤ li ≤ ri ≤ 1012。

解题思路:

根据题目要求我们可以知道

这题主要要会求前N项和的求和公式:(首项+末项)*项数/2

所以解题思路是,我们先将每一行看做一起的,做一个前缀和的预处理,比如2,就代表前两行的和,然后我们可以将一个下标L从1开始到本身的和,拆成他的上一行的前缀和+本行的几个元素的和,所以我们写一个函数sum1(z),去找出他的上一行,再加上它本身的几个元素并返回,由于题目是求字段和,所以我们L的位置的数也要加进来,最终就是sum1(r) - sum1(l - 1)

#include<bits/stdc++.h>
using namespace std;

#define ll long long
//通过公式算出结果是1580000多行
const ll maxn = 16e5;
ll sum[maxn];

//js()是首相加末项乘项数除二
ll js(ll i)
{
    return (1 + i) * i / 2;
}

ll sum1(ll z)
{
    //处理L等于1时,L-1为0
    if(z == 0)return 0;
    //同上maxn
    ll l = 1, r = maxn;
    while(l <= r)
    {
        ll mid = (l + r) >> 1;
        if(js(mid) < z)l = mid + 1;
        else r = mid - 1;
    }
    //因为上面循环保证了r是在z所处行的上一行,所以前缀和[R]要加上下一行的几个元素
    //z-r是总下标减去上面前缀和的标
    return sum[r] + js(z - js(r));
}

int main()
{
    //之所以用sacnf printf是因为数据很多,用cin cout很慢

    ll t, len = 0;
    //cin >> t;
    scanf("%lld",&t);
    //用len控制元素个数
    for(ll i = 1; len <= 1e12; i++)
    {
        //每一次加上一行
        len += i;
        //前缀和处理
        sum[i] = sum[i-1] + js(i);
    }
    while(t--)
    {
        ll l, r;
        //cin >> l >> r;
        scanf("%lld %lld",&l,&r);
        //L - 1是因为题目求从L-R的字段和
        //cout << sum1(r) - sum1(l - 1) << endl;
        printf("%lld\n",sum1(r) - sum1(l - 1) );
    }
    return 0;
}

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员shy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值