【模拟】AcWing 155. 内存分配

有点毒瘤的模拟。

我用 \(\texttt{set}\)​ 乱搞编写了一个数据结构来维护,发现比很多人的代码跑得快,甚至在洛谷最优解前列,但是码量大了不少。

分析

实现的思路比较明显:

记一共有 \(m\) 个进程。

  • 我们从 \(1\to m\) 枚举每个进程并进行处理。
  • 在处理到第 \(i\)​​ 个进程前,我们先进行结算(\(\texttt{account}\)​​​​),就是将在第 \(i\)​​ 个进程所在的申请时刻之前能够结束的进程全部清除,并将等待队列中能够被加入的进程加入内存中。
  • 然后对于当前进程:如果有足够的空间,那么就丢进去;反之,将其加入等待队列中。

可以发现,上面的模拟过程涉及对区间的赋值:当内存被占用的时候记为 \(1\),反之为 \(0\)。

对此,可以使用一个 \(\texttt{set}\) 来维护区间:

区间有三个属性:左右端点 \(l, r\),值 \(val(0/1)\)。

维护两种操作:

  • \(\texttt{find(len):}\)​​ 直接对 \(\texttt{set}\)​ 的元素(即区间)进行遍历,当区间值为 \(0\)​​ 且长度 \(\geq len\) 时,返回该区间的左端点,如果没有则返回 \(-1\)。
  • \(\texttt{eval(l, r, val):}\) 即区间赋值操作,当 \(val=0\) 时,也就是原来的区间从 \(1\to 0\),故检查该区间左、右区间是否也是 \(0\),如果是则需要进行合并再插入 \(\texttt{set}\);当 \(val=1\) 直接进行值的修改即可。​​

实现

// Problem: 内存分配
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/157/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
using namespace std;

#define debug(x) cerr << #x << ": " << (x) << endl
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define dwn(i,a,b) for(int i=(a);i>=(b);i--)
#define pb push_back
#define all(x) (x).begin(), (x).end()

#define x first
#define y second
using pii = pair<int, int>;
using ll = long long;

inline void read(int &x){
    int s=0; x=1;
    char ch=getchar();
    while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
    while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
    x*=s;
}

const int N=10010;

int n, m, ts, res;

struct Event{
    int t, m, p;
}e[N];

struct Cmd{
    int t, l, r; // end time, [l, r]
    bool operator < (const Cmd &o)const{
        return t>o.t;
    }
};
priority_queue<Cmd> clk;

queue<pii> q;

struct Seg{
    int l, r;
    mutable bool val;

    bool operator < (const Seg &o)const{
        return l<o.l;
    }

    int len(){
        return r-l+1;
    }
};
set<Seg> st;

int find(int len){
    for(auto i: st) if(!i.val && i.len()>=len) return i.l; 
    return -1;
}

void eval(int l, int r, bool val){
    auto it=--st.upper_bound({l, 0, 0});
    if(val){
        int L=it->l, R=it->r;
        st.erase(it);

        if(L<=l-1) st.insert({L, l-1, 0});
        if(r+1<=R) st.insert({r+1, R, 0});
        st.insert({l, r, 1});
    }
    else{
        auto L=it, R=it;
        if(it!=begin(st)) L--;
        if(it!=end(st)) R++;

        auto seg=*it;
        if(it!=L && L->val==0) seg.l=L->l, st.erase(L);
        if(R!=end(st) && R->val==0) seg.r=R->r, st.erase(R);
        seg.val=0;

        st.erase(it);
        st.insert(seg);
    }
}

void account(int lim){
    while(clk.size() && clk.top().t<=lim){
        auto tmp=clk.top(); clk.pop();
        ts=tmp.t;

        int l=tmp.l, r=tmp.r;
        eval(l, r, 0);
        if(clk.size() && clk.top().t==tmp.t) continue;

        int k;
        while(q.size() && (k=find(q.front().x))!=-1){
            auto [x, y]=q.front(); q.pop();
            eval(k, k+x-1, 1);
            clk.push({ts+y, k, k+x-1});
        }
    }
}

int main(){
    cin>>n;
    int a, b, c;
    while(cin>>a>>b>>c, a || b || c) e[++m]={a, b, c};

    st.insert({1, n, 0});
    rep(i,1,m){
        account(e[i].t);

        int k=find(e[i].m);
        ts=e[i].t;

        if(~k){
            int l=k, r=k+e[i].m-1;
            eval(l, r, 1);
            clk.push({ts+e[i].p, l, r});
        }
        else{
            q.push({e[i].m, e[i].p});
            res++;
        }
    }
    account(2e9+5);

    cout<<ts<<endl<<res<<endl;

    return 0;
}

上一篇:【并发编程】支持按优先级排序的*阻塞队列PriorityBlockingQueue


下一篇:CF1637A Sorting Parts 题解