码迷,mamicode.com
首页 > 其他好文 > 详细

[Bzoj]5343: [Ctsc2018]混合果汁

时间:2018-12-13 14:25:40      阅读:211      评论:0      收藏:0      [点我收藏+]

标签:n+1   eve   ret   date   max   小朋友   stdout   算法   输入输出格式   

5343: [Ctsc2018]混合果汁


题目描述

小 R 热衷于做黑暗料理,尤其是混合果汁。

商店里有 \(n\) 种果汁,编号为 \(0,1,\cdots,n-1\)\(i\) 号果汁的美味度是 \(d_i\),每升价格为 \(p_i\)。小 R 在制作混合果汁时,还有一些特殊的规定,即在一瓶混合果汁中,\(i\) 号果汁最多只能添加 \(l_i\) 升。

现在有 \(m\) 个小朋友过来找小 R 要混合果汁喝,他们都希望小 R 用商店里的果汁制作成一瓶混合果汁。其中,第 \(j\) 个小朋友希望他得到的混合果汁总价格不大于 \(g_j\),体积不小于 \(L_j\)。在上述这些限制条件下,小朋友们还希望混合果汁的美味度尽可能地高,一瓶混合果汁的美味度等于所有参与混合的果汁的美味度的最小值。请你计算每个小朋友能喝到的最美味的混合果汁的美味度。

输入输出格式

输入格式:

输入第一行包含两个正整数 \(n, m\),表示果汁的种数和小朋友的数量。接下来 \(n\) 行,每行三个正整数 \(d_i, p_i, l_i\),表示 \(i\) 号果汁的美味度为 \(d_i\),每升价格为\(p_i\),在一瓶果汁中的添加上限为 \(l_i\)

接下来 \(m\) 行依次描述所有小朋友:每行两个数正整数 \(g_j, L_j\)描述一个小朋友,表示他最多能支付 \(g_j\) 元钱,他想要至少 \(L_j\) 升果汁。

输出格式:

对于所有小朋友依次输出:对于每个小朋友,输出一行,包含一个整数,表示他能喝到的最美味的混合果汁的美味度。如果无法满足他的需求,则输出 \(-1\)

说明

对于所有的测试数据,保证 \(n, m \le 100000\)\(1 \le d_i,p_i,l_i \le 10^5, 1 \le g_j, L_j \le 10^{18}\)

测试点编号 \(n=\) \(m=\) 其他限制
1,2,3 \(10\) \(10\)
4,5,6 \(500\) \(500\)
7,8,9 \(5000\) \(5000\)
10,11,12 \(100000\) \(100000\) \(p_i=1\)
13,14,15 \(100000\) \(100000\) \(l_i=1\)
16,17,18,19,20 \(100000\) \(100000\)

题目分析:

考虑大暴力。

假设枚举所有的\(d\),可以发现从大到小答案是单调的。

那么我们先按照\(d\)排一遍序,然后二分这个\(d\),对于每个d直接暴力寻找是否可以满足条件,不难发现这个算法复杂度是\(O(n^2log^2n)\)的。

思考如何优化掉一个\(n\),发现可以对价格建立一棵权值线段树,然后对于二分的\(d\)就查询当前的状态是否能够满足总价格小于\(g\),发现这个\(d\)是可持久化的,可以用主席树实现。

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+7;
#define ll long long
#define mid ((l+r>>1))
struct Node{
    int d,p,l;
    bool operator <(const Node &rhs)const{return d<rhs.d;}
}a[MAXN];
struct Segtree{
    ll v,w;
}st[MAXN<<5];
int L[MAXN<<5],R[MAXN<<5],T[MAXN],size;
int n,m;
ll g,lim;
inline ll read()
{
    ll x=0,c=1;char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    while(ch=='-') c*=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return c*x;
}
int update(int pre,int l,int r,int x,int v,ll w)
{
    int rt=++size;
    L[rt]=L[pre],R[rt]=R[pre],st[rt].v=st[pre].v+v,st[rt].w=st[pre].w+w;
    if(l==r) return rt;
    if(x<=mid) L[rt]=update(L[pre],l,mid,x,v,w);
    else R[rt]=update(R[pre],mid+1,r,x,v,w);
    return rt;
}
ll query(int v,int l,int r,ll x)
{
    if(l==r) return (ll)x*l;
    if(st[L[v]].v>=x) return query(L[v],l,mid,x);
    else return st[L[v]].w+query(R[v],mid+1,r,x-st[L[v]].v);
}
ll solve()
{
    g=read();lim=read();
    if(lim>g) return -1;
    int l=0,r=n,ans=0;
    while(l<=r){
        ll Mid=l+r>>1;
        ll d=query(T[Mid],1,MAXN,lim);
        if(lim<=st[T[Mid]].v&&d<=g) ans=Mid,l=Mid+1;
        else r=Mid-1;
    }
    return a[ans].d;
}
int main()
{
//  freopen("data.in","r",stdin);
//  freopen("my.out","w",stdout);
    n=read();m=read();
    for(int i=1;i<=n;i++){
        a[i].d=read();a[i].p=read();a[i].l=read();
    }
    sort(a+1,a+n+1);
    a[0].d=-1;
    T[n+1]=++size;
    for(int i=n;i>=1;i--){
        T[i]=update(T[i+1],1,MAXN,a[i].p,a[i].l,(ll)a[i].l*a[i].p);
    }
    T[0]=T[1];
    while(m--)  printf("%lld\n",solve());
    return 0;
}

[Bzoj]5343: [Ctsc2018]混合果汁

标签:n+1   eve   ret   date   max   小朋友   stdout   算法   输入输出格式   

原文地址:https://www.cnblogs.com/victorique/p/10113602.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!