gym102411H. High Load Database(整体二分)

                                                        H. High Load Database

time limit per test

2 seconds

memory limit per test

512 megabytes

input

standard input

output

standard output

Henry profiles a high load database migration script. The script is the list of nn transactions. The ii-th transaction consists of aiai queries. Henry wants to split the script to the minimum possible number of batches, where each batch contains either one transaction or a sequence of consecutive transactions, and the total number of queries in each batch does not exceed tt.

Unfortunately, Henry does not know the exact value of tt for the production database, so he is going to estimate the minimum number of batches for qq possible values of tt: t1,t2,…,tqt1,t2,…,tq. Help Henry to calculate the number of transactions for each of them.

Input

The first line contains a single integer nn — the number of transactions in the migration script (1≤n≤2000001≤n≤200000).

The second line consists of nn integers a1,a2,…,ana1,a2,…,an — the number of queries in each transaction (1≤ai1≤ai; ∑ai≤106∑ai≤106).

The third line contains an integer qq — the number of queries (1≤q≤1000001≤q≤100000).

The fourth line contains qq integers t1,t2,…,tqt1,t2,…,tq (1≤ti≤∑ai1≤ti≤∑ai).

Output

Output qq lines. The ii-th line should contain the minimum possible number of batches, having at most titi queries each. If it is not possible to split the script into the batches for some titi, output "Impossible" instead.

Remember that you may not rearrange transactions, only group consecutive transactions in a batch.

Example

input

Copy

6
4 2 3 1 3 4
8
10 2 5 4 6 7 8 8

output

Copy

2
Impossible
4
5
4
3
3
3

 

一、地址链接

点我传送

 

二、大致题意

  给定n个数a1.a2.. ai 。

  询问Q次,每次询问给定一个 ti ,你可以做的操作是合并一段或者多段连续的区间(即区间累加),使得剩下来的区间,大小不能超过 ti ,在每个询问回答最少能合并成多少个区间。

 

三、大致思路

  看到好多题解的思路是小数据暴力预处理出来,然后大数据直接二分前缀和求答案。复杂经过分析是调和级数。

  惊叹实在是太巧妙了。但是这里贴出来的是一种更加暴力的整体二分做法。

  先思考一下,如果在一个值ti下,这些数能够被分割成mid块,那么肯定也可以被分割成mid+1...mid+2..mid+3或者更多块。这是一定的。那么这里显然就存在着可以被二分的性质。

  再分析一下,如果现在明确的告诉你要将原本的数列分割成K个区间,那么我肯定可以二分出一个最大值的最小值 minMax,那么结合上面的性质——如果当前我整体二分到的一个值qry是大于等于minMax的,那么这个qry值应该在左区间去被check,反之则应归在右区间。这样整体二分的思路就明确了。

  这个复杂度蒟蒻不太会算QAQ。我觉得应该是    (q^1.5) (logn)^2 。

 

四、丑陋代码

#include<cstring>
#include<cstdio>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
inline int Read()
{
    int x=0,f=1;char c=getchar();
    while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
    return x*f;
}
const int N=2e5+5;
struct node{int k,id;}qry[N<<1],ql[N<<1],qr[N<<1];
int n,m;
int val[N],ans[N],sum,maxx,cum[N];

int check(int mid)
{
    int l=0,cnt=0;
    while(l<n)
    {
        l=upper_bound(cum+l,cum+1+n,cum[l]+mid)-cum-1;
        cnt++;
    }
    return cnt;
}

int bir(int K)
{
    int l=maxx,r=sum;
    int ret=sum,mid;
    while(l<=r)
    {
        mid=(l+r)>>1;
        if(check(mid)<=K)
        {
            ret=mid;
            r=mid-1;
        }
        else l=mid+1;
    }
    return ret;
}

void divide(int l,int r,int s,int t)
{
    if(s>t) return;
    if(l==r)
    {
        for(int i=s;i<=t;i++)
        {
            if(qry[i].k<maxx)ans[qry[i].id]=-1;
            else ans[qry[i].id]=l;
        }
        return;
    }
    int mid=(l+r)>>1,lp=0,rp=0;
    int maxMin=bir(mid);

    for(int i=s;i<=t;i++)
    {
        if(qry[i].k>=maxMin)ql[++lp]=qry[i];
        else qr[++rp]=qry[i];
    }

    for(int i=s;i<=s+lp-1;i++) qry[i]=ql[i+1-s];
    for(int i=s+lp;i<=t;i++) qry[i]=qr[i+1-s-lp];
    divide(l,mid,s,s+lp-1),divide(mid+1,r,s+lp,t);
}


int main()
{
    n=Read();
    maxx=sum=0;
    for(int i=1;i<=n;i++)val[i]=Read(),sum+=val[i],maxx=max(maxx,val[i]),cum[i]=cum[i-1]+val[i];
    m=Read();
    for(int i=1;i<=m;i++)
    {
        qry[i].k=Read();
        qry[i].id=i;
    }
    divide(1,n,1,m);
    for(int i=1;i<=m;i++)
    {
        if(ans[i]==-1)printf("Impossible\n");
        else
            printf("%d\n",ans[i]);
    }
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值