CodeForces 734C Anton and Making Potions 二分或线段树


题意:

要制作n个药,初始制作一个药的时间为x,魔力值为s,有两类咒语可以加速,一类有m种咒语,每种咒语使制作一个药的时间变成a[i],花费b[i]的魔力,二类有k种咒语,每种咒语瞬间产生c[i]个药,花费d[i]的魔力,c[i]和d[i]都是不递减的,求最短时间内产生n个药的时间。

思路:

题目中明确说明了,对于第二类咒语,魔力值花的越多,瞬间产生的药也越多。所以我们可以枚举第一种咒语,二分最大的第二种咒语就行。

注意:每种咒语至多选一个,也可以不选。

二分代码:

#include <bits/stdc++.h>

using namespace std;
const int MAXN=200100;
long long a[MAXN];
long long b[MAXN];
long long c[MAXN];
long long d[MAXN];
int main(){
    ios::sync_with_stdio(false);
    long long num,num1,num2,x,s;
    while(cin>>num>>num1>>num2>>x>>s){

        for(int i=1;i<=num1;i++)
            cin>>a[i];
        for(int i=1;i<=num1;i++)
            cin>>b[i];
        for(int i=1;i<=num2;i++)
            cin>>c[i];
        for(int i=1;i<=num2;i++)
            cin>>d[i];
        a[0]=x;b[0]=c[0]=d[0]=0;
        long long ans=num*x;
        for(int i=0;i<=num1;i++){
            long long left=s-b[i];
            if(left<0) continue;
            int up=upper_bound(d,d+num2+1,left)-d;
            ans=min(ans,(num-c[up-1])*a[i]);
        }
        cout<<ans<<endl;
    }
}
这个题可以用二分做的原因是,第二类咒语,魔力值花的越多,瞬间产生的药也越多。但如果把题改成第二类咒语也是乱序的,即魔力值花的多的不一定产生的药多该怎么办呢?

最直接的想法是就同时枚举两种咒语,但由于数据量的问题,肯定会TLE。O(n^2)的算法不行,有O(nlogn)的算法吗?

我们可以先枚举确定一种咒语,对于另一种咒语,我们是想知道在剩下的魔力值内,最多能产生的药的数量,或产生一瓶药最少的时间。也就是说我们要知道在一个魔力值区间内产生药最大值或时间的最小值。这时,我们就需要线段树来帮忙。

先离散化魔力值,再以魔力值递增顺序建树,维护区间的最大值或最小值。对于每种选择,做一个logn的查询就行。

这样总的算法复杂度就在nlogn级别。


线段树代码:

#include <bits/stdc++.h>
#define ls l,mid,rt<<1
#define rs mid+1,r,(rt<<1)|1
#define mi (l+r)>>1
#define root l,r,rt

using namespace std;
const long long MAXN=200100;
const long long INF=0x3f3f3f3f3f3f3f3f;

typedef struct Node{
    long long x;
    long long y;
    Node(long long xx=0,long long yy=0){
        x=xx;y=yy;
    }
    bool operator < (const Node &a)const{
        if(a.y==y) return a.x>x;
        return a.y>y;
    }
}Node;
long long c[MAXN];
Node a[MAXN];
Node b[MAXN];
long long cut;
long long tree[4*MAXN];
long long st,en;

void push_up(long long l,long long r,long long rt){
    tree[rt]=min(tree[rt<<1],tree[(rt<<1)|1]);
    return ;
}
void build(long long l,long long r,long long rt){
    if(l==r){
        tree[rt]=a[cut++].x;
        return ;
    }
    long long mid=mi;
    build(ls);
    build(rs);
    push_up(root);
    return ;
}
long long query(long long l,long long r,long long rt){
    if(st<=l&&r<=en) return tree[rt];
    long long mid=mi;
    long long ans=INF;
    if(st<=mid)
        ans=min(ans,query(ls));
    if(mid<en)
        ans=min(ans,query(rs));
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    long long num,num1,num2,x,s;
    while(cin>>num>>num1>>num2>>x>>s){
        for(long long i=0;i<num1;i++)
            cin>>a[i].x;
        for(long long i=0;i<num1;i++){
            cin>>a[i].y;
            c[i]=a[i].y;						//c数组用于离散化,以确定区间的范围
        }
        for(long long i=1;i<=num2;i++)
            cin>>b[i].x;
        for(long long i=1;i<=num2;i++)
            cin>>b[i].y;
        b[0].x=0;b[0].y=0;
        sort(c,c+num1);sort(a,a+num1);sort(b,b+num2+1);
        cut=0;
        build(1,num1,1);
        //long long cut;
        long long ans=num*x;
        for(long long i=0;i<=num2&&ans;i++){
            long long left=s-b[i].y;
            if(left<0) continue;
            else{
                ans=min(ans,max((long long)0,(num-b[i].x)*x));
                if(ans==0) continue;
                en=upper_bound(c,c+num1,left)-c;			//二分确定区间终点
                st=1;							//由于是递增的区间起点一定是1
                if(en<st) continue;
                cut=query(1,num1,1);
                ans=min(ans,(num-b[i].x)*cut);
            }
        }
        cout<<ans<<endl;

    }
}

至于为什么会想到线段树的做法呢?

那还不简单........






























因为读错题了233333333333

ow he is stuck at one of the levels. To pass to the next level he has to prepare npotions.

Anton has a special kettle, that can prepare one potions in x seconds. Also, he knows spells of two types that can faster the process of preparing potions.

  1. Spells of this type speed up the preparation time of one potion. There are m spells of this type, the i-th of them costs bi manapoints and changes the preparation time of each potion to ai instead of x.
  2. Spells of this type immediately prepare some number of potions. There are k such spells, the i-th of them costs di manapoints and instantly create ci potions.

Anton can use no more than one spell of the first type and no more than one spell of the second type, and the total number of manapoints spent should not exceed s. Consider that all spells are used instantly and right before Anton starts to prepare potions.

Anton wants to get to the next level as fast as possible, so he is interested in the minimum number of time he needs to spent in order to prepare at least n potions.

Input

The first line of the input contains three integers nmk (1 ≤ n ≤ 2·109, 1 ≤ m, k ≤ 2·105) — the number of potions, Anton has to make, the number of spells of the first type and the number of spells of the second type.

The second line of the input contains two integers x and s (2 ≤ x ≤ 2·109, 1 ≤ s ≤ 2·109) — the initial number of seconds required to prepare one potion and the number of manapoints Anton can use.

The third line contains m integers ai (1 ≤ ai < x) — the number of seconds it will take to prepare one potion if the i-th spell of the first type is used.

The fourth line contains m integers bi (1 ≤ bi ≤ 2·109) — the number of manapoints to use the i-th spell of the first type.

There are k integers ci (1 ≤ ci ≤ n) in the fifth line — the number of potions that will be immediately created if the i-th spell of the second type is used. It's guaranteed that ci are not decreasing, i.e. ci ≤ cj if i < j.

The sixth line contains k integers di (1 ≤ di ≤ 2·109) — the number of manapoints required to use the i-th spell of the second type. It's guaranteed that di are not decreasing, i.e. di ≤ dj if i < j.

Output

Print one integer — the minimum time one has to spent in order to prepare n potions.

Sample Input

Input
20 3 2
10 99
2 4 3
20 10 40
4 15
10 80
Output
20
Input
20 3 2
10 99
2 4 3
200 100 400
4 15
100 800
Output
200

Hint

In the first sample, the optimum answer is to use the second spell of the first type that costs 10 manapoints. Thus, the preparation time of each potion changes to 4 seconds. Also, Anton should use the second spell of the second type to instantly prepare 15 potions spending 80 manapoints. The total number of manapoints used is 10 + 80 = 90, and the preparation time is 4·5 = 20 seconds (15 potions were prepared instantly, and the remaining 5 will take 4 seconds each).

In the second sample, Anton can't use any of the spells, so he just prepares 20 potions, spending 10 seconds on each of them and the answer is 20·10 = 200.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值