High Load Database Gym - 102411H (前缀和+二分查找)

题目出处
High Load Database Gym - 102411H
ICPC 2019-2020 North-Western Russia Regional Contest

原文

题意

给长度为n的整数序列。
询问q次, 每次给定一个整数t, 你要把给定的序列尽可能少的划分, 要求每部分的区间和不大于t.
最终输出最少划分区间的数目。

思路

这道题是很明显的前缀和+二分的题目。

因为涉及到区间和, 所以不难想到利用前缀和进行O(1)的化简。

而二分的地方在于:

  • 这个区间要么是不可能的
    即区间中的最大元素比给定的t大.

  • 除此之外的情况就是可以二分的了;
    因为这个区间一定被划分成1-n份, n份一定是可行的. 在对于区间[l, r]划分时, 我们希望尽可能的靠右去划分(因为要保证分割尽可能少), 所以直接套二分模板, 每次改变被划分的区间即可.

代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
const int N=2e6+10;
int a[N];
int ans[N];
int prefix[N];
int n,m;
int solve(int x)
{
    if(ans[x]) return ans[x];
    int step=0;
    int last=1;
    while(last<=n)
    {
        int pos=upper_bound(prefix+1,prefix+n+1,x+prefix[last-1])-prefix;//找出第一个大于等于last的数
        //cout<<pos<<"-->"<<endl;
        last=pos;
        step++;
    }
    return ans[x]=step;
}
signed main()
{
    scanf("%lld",&n);
    int maxx=-1;
    for(int i=1;i<=n;i++) scanf("%lld",&a[i]),maxx=max(maxx,a[i]);
    for(int i=1;i<=n;i++) prefix[i]=prefix[i-1]+a[i];
    scanf("%lld",&m);
    while(m--)
    {
        int x;
        scanf("%lld",&x);
        if(x<maxx) printf("Impossible\n");
        else printf("%lld\n",solve(x));
    }
    return 0;
}

posted @ 2022-10-21 20:26  kingwzun  阅读(19)  评论(0编辑  收藏  举报