牛客练习赛14 B-区间的连续段(倍增打表)

链接: https://www.nowcoder.com/acm/contest/82/B
来源:牛客网

题目描述

给你一个长为n的序列a和一个常数k

有m次询问,每次查询一个区间[l,r]内所有数最少分成多少个连续段,使得每段的和都 <= k

如果这一次查询无解,输出"Chtholly"

输入描述:

第一行三个数n,m,k
第二行n个数表示这个序列a
之后m行,每行给出两个数l r表示一次询问

输出描述:

输出m行,每行一个整数,表示答案

题解:
f[i][j]表示从i点右移2^j个<=k区间到达的右端点。
对于每一个点二分找到第一个<=k区间的最右端点,然后通过倍增
求出f[i][1]...f[i][n]

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll sum[1000004];
ll f[1000004][22];
int main()
{
    ll n,m,k;scanf("%lld%lld%lld",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
        ll x;scanf("%lld",&x);
        sum[i]=sum[i-1]+x;
    }
    for(int i=0;i<=21;i++)f[n+1][i]=n+1;
    for(int i=n;i>=1;i--)
    {
        f[i][0]=upper_bound(sum+i,sum+n+1,sum[i-1]+k)-sum;
        for(int j=1;j<=21;j++)
            f[i][j]=f[f[i][j-1]][j-1];
    }
    while(m--)
    {
        ll x,y;scanf("%lld%lld",&x,&y);
        ll ans=0;
        for(int i=21;i>=0;i--)
        {
            if(f[x][i]<=y)ans+=1<<i,x=f[x][i];
        }
        if(f[x][0]>y)printf("%lld\n",ans+1);
        else printf("Chtholly\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值