zoukankan      html  css  js  c++  java
  • nowcoder82B 区间的连续段

    题意:给你一个长为n的序列a和一个常数k, 有m次询问,每次查询一个区间[l,r]内所有数最少分成多少个连续段,使得每段的和都 <= k (1 <= n , m <= 1000000 , 1 <= ai , k <= 1000000000)

    题解:预处理,对于一个区间,它分的段数可以进行贪心进行处理,这里又用到了倍增的思想,dp[i][j]代表以i为起点的分2^j段的末尾下标,可以进行递推dp[i][j] = dp[dp[i][j-1]][j-1];

    #include <bits/stdc++.h>
    #define maxn 1000010
    #define INF 0x3f3f3f3f
    typedef long long ll;
    using namespace std;
    ll n, m, k, a[maxn], sum[maxn], dp[maxn][21];
    int main(){
        memset(dp, INF, sizeof(dp));
        scanf("%lld%lld%lld", &n, &m, &k);
        for(ll i=1;i<=n;i++)
            scanf("%lld", &a[i]);
        for(ll i=1;i<=n;i++)
            sum[i] = sum[i-1]+a[i];
        for(ll i=1;i<=n;i++){
            ll l = i, r = n, p = -1;
            while(l<=r){
                ll mid = (l+r)>>1;
                if((sum[mid]-sum[i-1])<=k)
                    l = mid+1, p = mid;
                else r = mid-1;
            }
            if(p != -1) dp[i][0] = p;
        }
        for(ll j=1;j<=20;j++){
            for(ll i=1;i<=n;i++)
                if(dp[i][j-1]+1 <= n)
                    dp[i][j] = dp[dp[i][j-1]+1][j-1];
        }
        ll x, y, ans;
        while(m--){
            scanf("%lld%lld", &x, &y);
            ans = 0;
            for(ll i=20;i>=0;i--){
                if(dp[x][i] <= y){
                    ans += (1<<i);
                    x = dp[x][i]+1;
                }
            }
            if(x<=y&&dp[x][0] >= y) ans++;
            if(sum[y]-sum[x-1] > k) printf("Chtholly
    ");
            else printf("%lld
    ", ans);
        }
        return 0;
    }
  • 相关阅读:
    4.12作业
    4.9上机作业
    第十周上级作业
    第九周上机作业
    第八周作业
    第八周上机作业
    第七周作业
    第七周上机练习
    第六周作业
    4.9上机练习
  • 原文地址:https://www.cnblogs.com/Noevon/p/8694905.html
Copyright © 2011-2022 走看看