区间的连续段(倍增,思维)

博客内容介绍了如何使用倍增思维解决区间分段问题。通过动态规划dp[i][j]来表示从位置i开始将序列分成2^j段所能达到的最大位置。初始化dp[n+1][i]=n+1,表示从n开始后面长度为2^i的子序列中,大于序列总和+k的位置。接着通过递推公式dp[i][j]=dp[dp[i][j-1]][j-1]进行计算。
摘要由CSDN通过智能技术生成

在这里插入图片描述
在这里插入图片描述

思路:用倍增思维来写。dp[i][j]表示从i开始吧序列分为2^j 段最多到哪。那么初始化就是dp[n+1][i]=n+1(他从n开始后面长度为2^i 中大于整个序列之和+k的位置是n+1)得到dp[i][j]=dp[dp[i][j-1]][j-1]

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <set>
#include <sstream>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<cmath>
#include<cctype>
#include<cstring>
#include<cstdlib>
#define MAXX 100005
#define SIS std::ios::sync_with_stdio(false)
#define ll long long
#define INF 0x3f3f3f3f
//#include<bits/stdc++.h>
using namespace std;
const int MAX =1e6+20;
const double PI = 3.14159265359;
//const int mod = 1e9 + 7;
ll a[MAX],b[MAX];
vector<int> vt[200005];
ll dp[MAX][25],dep[200005];



int main()
{
    int n,m,k;
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++)
    {
     scanf("%lld",&a[i]);
     b[i]=b[i-1]+a[i];
    }
    for(int i=0;i<=21;i++)
    {
        dp[n+1][i]=n+1;
    }
    for(int i=n;i>=1;i--)
    {
        dp[i][0]=upper_bound(b+1,b+1+n,b[i-1]+k)-b;
        for(int j=1;j<=21;j++)
            dp[i][j]=dp[dp[i][j-1]][j-1];
    }
    while(m--)
    {
        int l,r;
        scanf("%d%d",&l,&r);
         ll cnt=0;
         for(int i=21;i>=0;i--)
         {
             if(dp[l][i]<=r) cnt+=(1<<i),l=dp[l][i];
         }
         if(dp[l][0]>r)printf("%lld\n",cnt+1);
         else
         printf("Chtholly\n");


    }

    return 0;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值