[2017纪中11-1]背包 二分

来源:互联网 发布:ubuntu安装pyqt 编辑:程序博客网 时间:2024/06/07 06:52

题面
先考虑数据随机。先把物品排好序,每次二分出买的那个价格最大的物品,因为数据随机,买不了多少个就没钱了。
但构造的数据可以卡,于是考虑预处理一个价格前缀和,每次像之前一样二分出能卖的右端点R,然后在二分一个能取走的最长区间[L,R],一次把他们去玩。可以证明这样复杂度是O(nlog^2n)的,因为每次剩下的钱至少变成原来的一半。设钱数为M,[L,R]的价格和于M-C,假设M-C>M/2,那么L-1的价格C’>M-C>M/2,推出C’>C,矛盾。
代码:

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#define ll long longusing namespace std;const int maxn=100010;int n,m;ll s[maxn],r[maxn];struct node{    ll v,w;}a[maxn];bool operator <(const node& p,const node &q) {    if(p.v==q.v) return p.w<q.w;    return p.v<q.v;}int main(){    scanf("%d%d",&n,&m);    for(int i=1;i<=n;i++)        scanf("%lld%lld",&a[i].v,&a[i].w);    sort(a+1,a+n+1);    for(int i=1;i<=n;i++)    {        s[i]=s[i-1]+a[i].v;         r[i]=r[i-1]+a[i].w;    }    while(m--)    {        int p=n,R=n,q;        ll ans=0;        node c;c.w=1e13;        scanf("%lld",&c.v);        while(R>0&&c.v>0)        {            p=lower_bound(a+1,a+R+1,c)-a-1;            q=lower_bound(s,s+R+1,s[p]-c.v)-s;            c.v-=s[p]-s[q];            ans+=r[p]-r[q];            R=q;        }        printf("%lld\n",ans);    }    return 0;}