zoukankan      html  css  js  c++  java
  • 【时光回溯】【JZOJ3571】【GDKOI2014】内存分配

    题目描述

    这里写图片描述

    输入

    这里写图片描述

    输出

    输出m行,每行一个整数,代表输入中每次程序变化后系统所需要的空闲内存单位数。

    样例输入

    2 3
    1 4
    1 4
    2 2 1
    2 1 1
    1 1 1

    样例输出

    2
    3
    1

    数据范围

    对于30%的数据,有1<=n,m<=1000
    对于100%的数据,有1<=n,m<=100000

    样例解释

    这里写图片描述

    解法

    显然存在一种排列顺序,使得代价最小。
    考虑这个排列的方式:易得b[i]<=b[j]时,代价最小。
    感性证明:
    假设当前所需代价为x,初始为0。
    把所有代价小于等于x的程序立即完成,然后获得可以获得的内存。
    直到没有完成的程序后,立即分配一单位的内存。
    这样贪心可以保证正确性。


    考虑合并两个程序为一个等价的程序。
    (a1,b1)+(a2,b2)=(a1+a2,max(b1,b2a1))
    显然把所有程序合并起来就是答案。
    此外一个重要性质是,合并操作满足结合律。
    这样就可以利用线段树来处理程序的合并。
    离线处理即可。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #define ll long long
    #define sqr(x) ((x)*(x))
    #define ln(x,y) ll(log(x)/log(y))
    using namespace std;
    const char* fin="ex3571.in";
    const char* fout="ex3571.out";
    const ll inf=0x7fffffff;
    const ll maxn=100007*2,maxt=maxn*4;
    ll n,m,i,j,k,l,rank[maxn],b[maxn],d[maxn];
    struct prog{
        ll get,need,id;
        void operator=(const prog &b){
            get=b.get;
            need=b.need;
            id=b.id;
        }
        prog(){
            get=need=id=0;
        }
    }a[maxn],c[maxt];
    prog merge(prog a,prog b){
        prog c;
        c.need=max(a.need,b.need-a.get);
        c.get=a.get+b.get;
        return c;
    }
    bool cmp(prog a,prog b){
        return a.need<b.need;
    }
    void change(ll l,ll r,ll t,ll v,const prog &v1){
        ll mid=(l+r)/2;
        if (l==r){
            c[t]=v1;
            return ;
        }
        if (v<=mid) change(l,mid,t*2,v,v1);
        else change(mid+1,r,t*2+1,v,v1);
        c[t]=merge(c[t*2],c[t*2+1]);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for (i=1;i<=n;i++){
            scanf("%d%d",&a[i].get,&a[i].need);
            a[i].id=i;
        }
        for (i=n+1;i<=n+m;i++){
            scanf("%d%d%d",&b[i],&k,&l);
            a[i].need=l;
            a[i].get=k;
            a[i].id=i;
        }
        sort(a+1,a+n+m+1,cmp);
        for (i=1;i<=n+m;i++) rank[a[i].id]=i;
        for (i=1;i<=n;i++) change(1,n+m,1,rank[i],a[rank[i]]),d[i]=rank[i];
        for (i=n+1;i<=n+m;i++){
            change(1,n+m,1,d[b[i]],c[0]);
            change(1,n+m,1,rank[i],a[rank[i]]);
            d[b[i]]=rank[i];
            printf("%lld
    ",c[1].need);
        }
        return 0;
    }

    启发

    对于这类不同排列不同答案的问题。
    可以考虑合并元素;
    如果元素满足结合律,那么就可以使用线段树进行合并。

  • 相关阅读:
    6.12
    20121006晴
    6.11
    测试利器IL级别的Debug工具“Deblector1.1.1修改版”
    Windows Phone开发经验谈(15)动态的改变APP的字体大小
    windows8开发直播windows8商店开发者帐号注册过程(完)
    Windows Phone开发经验谈(13)华为网盘直链API调用
    windows8开发App审核折腾记
    Asp.net开发经验利用Aspose.Words按模板导出Word
    Windows Phone开发经验谈(17)两则改善用户体验的开发技巧
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714870.html
Copyright © 2011-2022 走看看