链接:
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;
}