[算法进阶0x10]基本数据结构A作业总结


在线题目\(oj\)评测地址:https://xoj.red/contests/show/1237

T1-Editor(hdu4699)

题目描述

维护一个整数序列的编辑器,有以下5种操作,操作总数不超过10^6。
I x:在当前光标位置之后插入一个整数x,插入后光标移动到x之后;
D:删除光标之前的一个整数,即相当于按下Backspace键;
L:光标左移一个位置,即按下左方向键
R:光标右移一个位置,即按下右方向键
Q k:询问在位置k之前的最大前缀和,其中k大于0且不超过当前光标的位置。

解法

因为光标是移动的,而且我们每次操作都是在光标附近,不难想到是用对顶栈来做,建立两个栈,分别维护当前光标左侧和右侧的序列。
我们定义数组\(sum\)记录前缀和,\(f\)数组是用\(dp\)来计算答案。

  • I插入操作就是:\(sum[top_a]=sum[top_a]+a[top_a]\)\(f[topa]=max(f[topa-1],sum[topa])\)
  • D操作就是:弹出\(a\)栈的栈顶。
  • L操作就是:弹出\(a\)栈的栈顶,弹入\(b\)栈中。
  • R操作就是:弹出\(b\)栈的栈顶,弹入\(a\)栈中,\(sum[top_a]=sum[top_a-1]+a[top_a]\)\(f[top_a]=max(f[top_a-1,sum[top_a]])\)
    这个玩意的复杂度很优,每次只需要\(O(1)\)处理就可以了。

    ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 1000005
int sum[N],f[N];
struct Stack{
    int top,s[N]; 
    Stack(){top=0;}
    void push(int x){s[++top]=x;}
    void pop(){--top;} 
    bool empty(){return top==0;}
}s1,s2;
int main(){
    ms(sum,0); ms(f,-inf);
    int n=gi();
    int pos=0;
    while (n--){
        char opt[5]; scanf("%s",opt); int x;
        if (opt[0]=='I') {
            x=gi();  s1.push(x);
            pos++; sum[pos]=sum[pos-1]+x; f[pos]=max(f[pos-1],sum[pos]);
        }
        if (opt[0]=='Q'){
            x=gi(); printf("%d\n",f[x]);
        }
        if (opt[0]=='L'){
            if (s1.empty())continue;
            --pos; int b=s1.s[s1.top]; s1.pop(); s2.push(b);
        }
        if (opt[0]=='D'){
            if (s1.empty()) continue;
            s1.pop(); pos--;
        }
        if (opt[0]=='R'){
            if (s2.empty()) continue;
            int b=s2.s[s2.top]; s2.pop();
            s1.push(b); ++pos; 
            sum[pos]=sum[pos-1]+b; f[pos]=max(f[pos-1],sum[pos]);
        }
    }
    return 0;
}

T2-火车进出栈问题

题目描述

一列火车n节车厢,依次编号为1,2,3,…,n。每节车厢有两种运动方式,进栈与出栈,问n节车厢出栈的可能排列方式有多少种。

解法

非常经典的问题,出栈的方案总数,就是卡特兰数,但是这道题目数据特别大,我们就把组合数分解出来,根据每一个合数的唯一分解定理,将答案转化成若干素数的若干次幂的形式。注意:要配上高精度

ac代码

# include <bits/stdc++.h>
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
# pragma GCC optimize(3)
# pragma GCC optimize(2)
# pragma GCC optimize(fast)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
struct BigInteger {
    typedef unsigned long long LL;
    static const int BASE = 100000000;
    static const int WIDTH = 8;
    vector<int> s;
    inline BigInteger& clean(){while(!s.back()&&s.size()>1)s.pop_back(); return *this;}
    inline BigInteger(LL num = 0) {*this = num;}
    inline BigInteger(string s) {*this = s;}
    inline BigInteger& operator = (long long num) {
        s.clear();
        do {
            s.push_back(num % BASE);
            num /= BASE;
        } while (num > 0);
        return *this;
    }
    inline BigInteger& operator = (const string& str) {
        s.clear();
        int x, len = (str.length() - 1) / WIDTH + 1;
        for (register int i = 0; i < len; i++) {
            int end = str.length() - i*WIDTH;
            int start = max(0, end - WIDTH);
            sscanf(str.substr(start,end-start).c_str(), "%d", &x);
            s.push_back(x);
        }
        return (*this).clean();
    }
    inline BigInteger operator + (const BigInteger& b) const {
        BigInteger c; c.s.clear();
        for (register int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= (int)s.size() && i >= (int) b.s.size()) break;
            int x = g;
            if (i < s.size()) x += s[i];
            if (i < b.s.size()) x += b.s[i];
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c;
    }
    inline BigInteger operator - (const BigInteger& b) const {
        assert(b <= *this);
        BigInteger c; c.s.clear();
        for (register int i = 0, g = 0; ; i++) {
            if (g == 0 && i >= s.size() && i >= b.s.size()) break;
            int x = s[i] + g;
            if (i < b.s.size()) x -= b.s[i];
            if (x < 0) {g = -1; x += BASE;} else g = 0;
            c.s.push_back(x);
        }
        return c.clean();
    }
    inline BigInteger operator * (const BigInteger& b) const {
        register int i, j; LL g;
        vector<LL> v(s.size()+b.s.size(), 0);
        BigInteger c; c.s.clear();
        for(i=0;i<s.size();i++) for(j=0;j<b.s.size();j++) v[i+j]+=LL(s[i])*b.s[j];
        for (i = 0, g = 0; ; i++) {
            if (g ==0 && i >= v.size()) break;
            LL x = v[i] + g;
            c.s.push_back(x % BASE);
            g = x / BASE;
        }
        return c.clean();
    }
    inline BigInteger operator / (const BigInteger& b) const {
        assert(b > 0); 
        BigInteger c = *this; 
        BigInteger m;
        for (register int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
            m -= b*c.s[i];
        }
        return c.clean();
    }
    inline BigInteger operator % (const BigInteger& b) const {
        BigInteger c = *this;
        BigInteger m;
        for (register int i = s.size()-1; i >= 0; i--) {
            m = m*BASE + s[i];
            c.s[i] = bsearch(b, m);
            m -= b*c.s[i];
        }
        return m;
    }
    inline int bsearch(const BigInteger& b, const BigInteger& m) const{
        int L = 0, R = BASE-1, x;
        while (1) {
            x = (L+R)>>1;
            if (b*x<=m) {if (b*(x+1)>m) return x; else L = x;}
            else R = x;
        }
    }
    inline BigInteger& operator += (const BigInteger& b) {*this = *this + b; return *this;}
    inline BigInteger& operator -= (const BigInteger& b) {*this = *this - b; return *this;}
    inline BigInteger& operator *= (const BigInteger& b) {*this = *this * b; return *this;}
    inline BigInteger& operator /= (const BigInteger& b) {*this = *this / b; return *this;}
    inline BigInteger& operator %= (const BigInteger& b) {*this = *this % b; return *this;}
 
    inline bool operator < (const BigInteger& b) const {
        if (s.size() != b.s.size()) return s.size() < b.s.size();
        for (register int i = s.size()-1; i >= 0; i--)
            if (s[i] != b.s[i]) return s[i] < b.s[i];
        return false;
    }
    inline bool operator >(const BigInteger& b) const{return b < *this;}
    inline bool operator<=(const BigInteger& b) const{return !(b < *this);}
    inline bool operator>=(const BigInteger& b) const{return !(*this < b);}
    inline bool operator!=(const BigInteger& b) const{return b < *this || *this < b;}
    inline bool operator==(const BigInteger& b) const{return !(b < *this) && !(b > *this);}
};
inline ostream& operator << (ostream& out, const BigInteger& x) {
    out << x.s.back();
    for (int i = x.s.size()-2; i >= 0; i--) {
        char buf[20];
        sprintf(buf, "%08d", x.s[i]);
        for (int j = 0; j < strlen(buf); j++) out << buf[j];
    }
    return out;
}
inline istream& operator >> (istream& in, BigInteger& x) {
    string s;
    if (!(in >> s)) return in;
    x = s;
    return in;
}
# define N 1000005
bool isprime[N];
int prime[N];
int cnt;
inline void get_prime(int maxn){
    for (register int i=2;i<maxn;++i) isprime[i]=true;
    for (register int i=2;i<maxn;++i){
        if (isprime[i]) prime[cnt++]=i;
        for (register int j=0;j<cnt&&i*prime[j]<maxn;++j){
            isprime[i*prime[j]]=false;
            if (i%prime[j]==0) break;
        }
    }
}
BigInteger ans;
inline BigInteger power(int x,register int n){
    BigInteger res=1,b=x;
    while (n){
        if (n&1) res=res*b;
        b*=b;
        n>>=1;
    }
    return res;
}
int main(){
    int n=gi();
    get_prime(120000);
    ans=1;
    for (register int i=0;i<cnt&&prime[i]<=2*n;++i){
        int sum=0,p=prime[i];
        register int t=n*2; 
        while (t>0) sum+=t/p,t/=p;
        t=n; 
        while (t>0) sum-=t/p*2,t/=p;
        ans=ans*(power(p,sum));
    }
    cout<<ans/(n+1)<<endl;
    return 0;
}

T3-2630: 表达式计算(4)

题目描述

给出一个表达式,其中运算符仅包含+,-,*,/,^要求求出表达式的最终值,数据可能会出现括号情况,还有可能出现多余括号情况数据保证不会出现>maxlongint的数据,数据可能回出现负数情况。

解法

非常经典的栈问题,做好优先级的判断和括号的匹配就好了,注意细节。(代码太长不放了)

T4-1803 City Game

题目描述

有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。
这片土地被分成NM个格子,每个格子里写着'R'或者'F',R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。
现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着'F'并且面积最大。
但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们每人给你3
S两银子。

解法

比较经典的问题,01的最大子矩阵。
动态规划,定义状态是\(f[i][j]\)表示以第\((i,j)\)为结尾的,这里一列上最长连续的有多少个。
那么用\(l\)\(r\)数组遍历计算出该点向左右两边延伸的左右边界,然后计算出最大值。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 1005
int f[N][N],l[N],r[N];
int n,m;
int main(){
    n=gi(),m=gi();
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++){
            char s[5]; scanf("%s",s);
            if (s[0]=='F') f[i][j]=f[i-1][j]+1;
            else f[i][j]=0;
        }
    }
    int ans=-inf;
    for (int i=1;i<=n;i++){
        for (int j=1;j<=m;j++) l[j]=r[j]=j;
        l[0]=1; r[m+1]=m; f[i][0]=-1; f[i][m+1]=-1;
        for (int j=1;j<=m;j++) while (f[i][l[j]-1]>=f[i][j]) l[j]=l[l[j]-1];
        for (int j=m;j>=1;j--) while (f[i][r[j]+1]>=f[i][j]) r[j]=r[r[j]+1];
        for (int j=1;j<=m;j++) while (f[i][j]*(r[j]-l[j]+1)>ans) ans=f[i][j]*(r[j]-l[j]+1);
    }
    printf("%d\n",ans*3);
    return 0;
}

T5- Largest Rectangle in a Histogram(poj2559)

题目描述

A histogram is a polygon composed of a sequence of rectangles aligned at a common base line. The rectangles have equal widths but may have different heights. For example, the figure on the left shows the histogram that consists of rectangles with the heights 2, 1, 4, 5, 1, 3, 3, measured in units where 1 is the width of the rectangles:

Usually, histograms are used to represent discrete distributions, e.g., the frequencies of characters in texts. Note that the order of the rectangles, i.e., their heights, is important. Calculate the area of the largest rectangle in a histogram that is aligned at the common base line, too. The figure on the right shows the largest aligned rectangle for the depicted histogram.

题目大意

求包含于这些矩形的并集内部的最大的矩形面积(如图中的阴影部分就是最大的)

解法

还是最大矩阵面积,这道题提供和上面不一样的做法,单调栈维护最大矩阵面积。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 100005
struct node{
    int h,s;
}stack[N];
LL best,ans;
int tmp,n,top,a[N];
int main(){
    while (1) {
        best=0;
        scanf("%d",&n);
        if (n==0) break;
        for (int i=1;i<=n;i++) a[i]=gi();
        for (int i=1;i<=n;i++){
            tmp=0;
            while (top!=0 && stack[top].h>=a[i]){
                tmp+=stack[top].s;
                ans=1ll*tmp*stack[top].h;
                if (ans>best) best=ans;
                --top;
            }
            stack[++top].h=a[i]; stack[top].s=tmp+1;
        }
        tmp=0;
        while (top!=0){
            tmp+=stack[top].s; 
            ans=1ll*tmp*stack[top].h;
            if (ans>best) best=ans;
            --top;
        }
        printf("%lld\n",best);
    }
    return 0;
}

T6-Sliding Window 滑窗(poj2823)

题目描述

给你一个长度为N的数组,一个长为K滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:
Window position Min value Max value
[1 3 -1] -3 5 3 6 7 -1 3
1 [3 -1 -3 ] 5 3 6 7 -3 3
1 3 [-1 -3 5] 3 6 7 -3 5
1 3 -1 [-3 5 3] 6 7 -3 5
1 3 -1 -3 [5 3 6] 7 3 6
1 3 -1 -3 5 [3 6 7] 3 7
你的任务是找出窗口在各位置时的Max value ,Min value。

解法

单调队列模板题,但是在\(poj\)上需要卡常才能过掉。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
# pragma GCC optimize(2)
# pragma GCC optimize(3)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 1000005
deque<int>qmax,qmin;
int ansmin[N],ansmax[N],a[N];
int n,k;
void write(int x){
    if (x<0){putchar('-');write(-x);return;}
    if (x>9) write(x/10);
    putchar(x%10+'0');
}
int main(){
    n=gi(),k=gi();
    for (int i=1;i<=n;i++) a[i]=gi();
    for (int i=1;i<=n;i++){
        while (!qmax.empty()&&i-qmax.front()+1>k) qmax.pop_front();
        while (!qmin.empty()&&i-qmin.front()+1>k) qmin.pop_front();
        while (!qmax.empty()&&a[i]>a[qmax.back()]) qmax.pop_back();
        while (!qmin.empty()&&a[i]<a[qmin.back()]) qmin.pop_back();
        qmax.push_back(i); qmin.push_back(i); 
        ansmax[i]=a[qmax.front()]; ansmin[i]=a[qmin.front()];
    }
    for (int i=k;i<=n;i++) {write(ansmin[i]);putchar(' ');} puts("");
    for (int i=k;i<=n;i++) write(ansmax[i]),putchar(' '); 
    return 0;
}

T7-双端队列(bzoj2457)

题目描述

Sherry现在碰到了一个棘手的问题,有N个整数需要排序。
Sherry手头能用的工具就是若干个双端队列。
她需要依次处理这N个数,对于每个数,Sherry能做以下两件事:
1.新建一个双端队列,并将当前数作为这个队列中的唯一的数;
2.将当前数放入已有的队列的头之前或者尾之后。
对所有的数处理完成之后,Sherry将这些队列排序后就可以得到一个非降的序列。

题解

我们以权值为第一关键字,编号为第二关键子排序,之后模拟反的过程,如果要一个双端队列和法,那么他们所取的编号一定是先下降然后上升的,这样我们贪心,每次的元素尽量放到一个双端队列里,模拟一遍就可以了。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define N 200005
using namespace std;
struct node{
    int v,ps;
}a[N*2];
int n;
int mx[N],mi[N],cnt=0;
int ans=0,flag=1,now=1<<30;
bool cmp(const node A,const node B){return A.v<B.v||(A.v==B.v&&A.ps<B.ps);}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i].v),a[i].ps=i;
    sort(a+1,a+n+1,cmp);
    for(int i=1;i<=n;i++){
        if(i==1||a[i].v!=a[i-1].v){
            mx[cnt]=a[i-1].ps;
            mi[++cnt]=a[i].ps;
        }
    }
    mx[cnt]=a[n].ps;
    for(int i=1;i<=cnt;i++){
        if(flag==0){
            if(now>mx[i]) now=mi[i];
            else now=mx[i],flag=1;
        }
        else{
            if(now<mi[i]) now=mx[i];
            else flag=0,now=mi[i],ans++;
        }
    }
    printf("%d\n",ans);
    return 0;
}

T8-最大连续M长子序列之和(单调队列优化DP模板)

题目描述

输入一个长度为n的整数序列,从中找出一段不超过M的连续子序列,使得整个序列的和最大。
例如 1, -3, 5, 1, -2, 3
当m=4时,S=5+1-2+3=7
当m=2或m=3时,S=5+1=6

题解

\(f[i]\)表示以前\(i\)个的最大答案,转移就是\(f[i]=max(f[i-1],sum[i]-sum[j-1])\)其中\(j\)是在\(m\)的范围里的,那么我们就单调队列维护\(sum\)前缀和的最小值。

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf (0x7f7f7f7f)
# define pb push_back
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
# define N 300005
deque<int>q;
int n,m;
int sum[N],f[N];
int main(){
    n=gi(),m=gi();
    for (int i=1;i<=n;i++) sum[i]=sum[i-1]+gi();
    q.push_back(0);
    for (int i=1;i<=n;i++){
        while (i-q.front()>m) q.pop_front();
        f[i]=max(f[i-1],sum[i]-sum[q.front()]);
        while (!q.empty()&&sum[q.back()]>sum[i]) q.pop_back(); 
        q.push_back(i); 
    }
    printf("%d\n",f[n]);
    return 0;
}

T9-1301 邻值查找

题目描述

给定一个长度为 n 的序列 A,A 中的数各不相同。对于 A 中的每一个数 A_i,求:
min(1≤j<i) ⁡|A_i-A_j|
以及令上式取到最小值的 j(记为 P_i)。若最小值点不唯一,则选择使 A_j 较小的那个。

题解

通过定义结构体和重载运算符,将set维护成一个有序的集合,
每次插入前,去找到当前这个数字最接近的值的前驱和后驱,比较前驱和后驱,找到最小的j,
如果找不到大于等于这个数字,能么需要判断end()(注意stl中全部都是以左闭右开的形式来保存的),去直接输出end()-1,同理如果是begin(),直接输出begin()+1

ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf 0x3f3f3f3f
# define pb push_back
# define dd double
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
inline int gi(){
    int w=0,x=0;char ch=0;
    while(!isdigit(ch)) w|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    return w?-x:x;
}
struct node{
    int num,id;
    bool operator<(node a) const{
        return num<a.num;
    }
};
set<node>s;
int main(){
    int n=gi(); 
    for(int i=1;i<=n;i++){
        int tmp=gi();
        if(i==1) {s.insert(node{tmp,i});continue;}
        set<node>::iterator right=s.lower_bound(node{tmp,0}),left=right;left--;
        if(right==s.end()) printf("%d %d\n",tmp-left->num,left->id);
        else if(right==s.begin()) printf("%d %d\n",right->num-tmp,right->id);
        else if((tmp-left->num)<=(right->num-tmp)) printf("%d %d\n",tmp-left->num,left->id);
        else printf("%d %d\n",right->num-tmp,right->id);
        s.insert(node{tmp,i});
    }
    return 0;
}

T10-Running Median

这道之前已经做过了,翻前面的博客吧!

T11-内存分配(NOI1999,bzoj3117)

题目描述

内存是计算机重要的资源之一,程序运行的过程中必须对内存进行分配。
经典的内存分配过程是这样进行的:

  • 内存以内存单元为基本单位,每个内存单元用一个固定的整数作为标识,称为地址。地址从0开始连续排列,地址相邻的内存单元被认为是逻辑上连续的。我们把从地址i开始的s个连续的内存单元称为首地址为i长度为s的地址片。
  • 运行过程中有若干进程需要占用内存,对于每个进程有一个申请时刻T,需要内存单元数M及运行时间P。在运行时间P内(即T时刻开始,T+P时刻结束),这M个被占用的内存单元不能再被其他进程使用。
  • 假设在T时刻有一个进程申请M个单元,且运行时间为P,则:
  • 若T时刻内存中存在长度为M的空闲地址片,则系统将这M个空闲单元分配给该进程。若存在多个长度为M个空闲地址片,则系统将首地址最小的那个空闲地址片分配给该进程。
  • 如果T时刻不存在长度为M的空闲地址片,则该进程被放入一个等待队列。对于处于等待队列队头的进程,只要在任一时刻,存在长度为M的空闲地址片,系统马上将该进程取出队列,并为它分配内存单元。注意,在进行内存分配处理过程中,处于等待队列队头的进程的处理优先级最高,队列中的其它进程不能先于队头进程被处理。
    现在给出一系列描述进程的数据,请编写一程序模拟系统分配内存的过程。

    题目大意

    给你\(n\)个操作,每一个操作都会占用一定的连续的内存和时间,求最少的时间和进入等待队列的操作的个数。

    解法

    开一个优先队列,按照起始和终止时间排序,然后用链表处理之间的操作。

    ac代码

# include <cstdio>
# include <cstring>
# include <algorithm>
# include <ctype.h>
# include <iostream>
# include <cmath>
# include <map>
# include <vector>
# include <queue>
# include <list>
# define LL long long
# define ms(a,b) memset(a,b,sizeof(a))
# define ri (register int)
# define inf 0x3f3f3f3f
# define pb push_back
# define dd double
# define fi first
# define se second
# define pii pair<int,int>
# define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
const int maxn=1e4+10;
int getint(){
    int res=0;
    char ch,ok=0;
    while(1){
        ch=getchar();
        if(isdigit(ch)){
            res*=10;res+=ch-'0';ok=1;
        }else if(ok)break;      
    }return res;
}
struct task{
    int t,m,p,f,ind;
    task(int _t=0,int _m=0,int _p=0,int _f=0,int _ind=0){
        t=_t,m=_m,p=_p,f=_f,ind=_ind;
    }
};
task tasks[maxn<<1];
int n,ans1,ans2,tot;
struct cmp{
    bool operator()(int a,int b){return tasks[a].t>tasks[b].t||(tasks[a].t==tasks[b].t&&tasks[a].f>tasks[b].f);}
};
priority_queue<int,vector<int>,cmp>que;
queue<int>q;
struct block{
    int l,r,ind,used;
    block(int _l=0,int _r=0,int _ind=0,int _used=0){
        l=_l,r=_r,ind=_ind,used=_used;
    }
};
list<block>List;
void deb(){
    for(list<block>::iterator it=List.begin();it!=List.end();it++)
    printf("l:%d r:%d ind:%d\t",it->l,it->r,it->ind);cout<<endl;
}
bool insert(int x){
    for(list<block>::iterator it=List.begin();it!=List.end();it++){
        if(!it->used&&(it->r-it->l+1>=tasks[x].m)){
            list<block>::iterator i=List.insert(++it,block(it->l,it->l+tasks[x].m-1,x,1));
            it=--i;i++;
            if(it->l+tasks[x].m-1<it->r)
            List.insert(++i,block(it->l+tasks[x].m,it->r,0,0));
            List.erase(it);
            return true;
        }
    }
    return false;
}
void erase(int x){
    if(List.size()==1){List.begin()->ind=0,List.begin()->used=0;return;}
    for(list<block>::iterator it=List.begin();it!=List.end();it++){
        if(it->ind==x){
            if(it==List.begin()){
                list<block>::iterator nxt=it;nxt++;
                if(!nxt->used){
                    List.insert(++nxt,block(1,nxt->r,0,0));
                    List.pop_front();List.pop_front();
                }else it->ind=0,it->used=0;
            }else
            if(it==--List.end()){
                list<block>::iterator pre=it;pre--;
                if(!pre->used){
                    List.insert(pre,block(pre->l,n,0,0));
                    List.pop_back();List.pop_back();
                }else it->ind=0,it->used=0;
            }else{
                list<block>::iterator pre=it;pre--;
                list<block>::iterator nxt=it;nxt++;
                if(!pre->used&&!nxt->used){
                    list<block>::iterator i=List.insert(pre,block(pre->l,nxt->r,0,0));
                    i++;
                    i=List.erase(i);i=List.erase(i);i=List.erase(i);
                }else
                if(!pre->used){
                    list<block>::iterator i=List.insert(pre,block(pre->l,it->r,0,0));
                    i++;
                    i=List.erase(i);i=List.erase(i);
                }else
                if(!nxt->used){
                    list<block>::iterator i=List.insert(it,block(it->l,nxt->r,0,0));                    
                    i++;
                    i=List.erase(i);i=List.erase(i);                    
                }else it->ind=0,it->used=0;
            }break;
        }
    }
}
int main(){
    n=getint();List.push_back(block(1,n,0,0));
    while(++tot){
        tasks[tot].t=getint(),tasks[tot].m=getint(),tasks[tot].p=getint();
        if(tasks[tot].t==0&&tasks[tot].m==0){tot--;break;}
        tasks[tot].f=1;tasks[tot].ind=tot;
        que.push(tot);
    }   
    while(!que.empty()){
        int top=que.top(),tt=top;
        ans1=max(ans1,tasks[top].t);
        if(tasks[top].f==1){
            que.pop();
            if(insert(top)){
                ++tot;
                tasks[tot]=tasks[top];
                tasks[tot].t=tasks[top].t+tasks[tot].p;ans1=max(ans1,tasks[tot].t);
                tasks[tot].f=-1;
                que.push(tot);
            }else{
                q.push(top);
                ans2++;
            }       
        }else{
            bool jj=0;
            while(que.size()>1){
                top=que.top();que.pop();
                int tp=que.top();
                if(tasks[top].f==-1){
                erase(tasks[top].ind);}
                else{
                    que.push(tp);
                    break;
                }
                if(tasks[top].f==-1&&tasks[tp].f==-1&&tasks[tp].t==tasks[top].t){
                }else {
                    jj=1;break;
                }
            }if(!que.empty()&&!jj){
                top=que.top();
                if(tasks[top].f==-1){
                erase(tasks[top].ind),que.pop();}
            }
            if(q.size())
            while(insert(q.front())){
                ++tot;
                tasks[tot]=tasks[q.front()];
                tasks[tot].t=tasks[tt].t+tasks[tot].p;ans1=max(ans1,tasks[tot].t);
                tasks[tot].f=-1;
                que.push(tot);
                q.pop();if(q.empty())break;             
            }
        }
    }
    printf("%d\n%d\n",ans1,ans2)
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/chhokmah/p/10482605.html
今日推荐