[算法进阶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,它们每人给你3S两银子。
解法
比较经典的问题,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;
}
[算法进阶0x10]基本数据结构A作业总结的更多相关文章
- [算法进阶0x10]基本数据结构C作业总结
t1-Supermarket 超市利润 题目大意 给定n个商品,每个商品有利润pi和过期时间di.每天只能卖一个商品,过期商品不能卖.求如何安排每天卖的商品可以使收益最大. 分析 一开始打了一个复杂度 ...
- 模板——最小生成树kruskal算法+并查集数据结构
并查集:找祖先并更新,注意路径压缩,不然会时间复杂度巨大导致出错/超时 合并:(我的祖先是的你的祖先的父亲) 找父亲:(初始化祖先是自己的,自己就是祖先) 查询:(我们是不是同一祖先) 路径压缩:(每 ...
- 《算法竞赛进阶指南》0x10 基本数据结构 Hash
Hash的基本知识 字符串hash算法将字符串看成p进制数字,再将结果mod q例如:abcabcdefg 将字母转换位数字(1231234567)=(1*p9+2*p8+3*p7+1*p6+2*p5 ...
- 「【算法进阶0x30】数学知识A」作业简洁总结
t1-Prime Distance 素数距离 大范围筛素数. t2-阶乘分解 欧拉筛素数后,按照蓝皮上的式子筛出素数. 复杂度:O(nlogn) t3-反素数ant 搜索 t4-余数之和 整除分块+容 ...
- 算法进阶之Leetcode刷题记录
目录 引言 题目 1.两数之和 题目 解题笔记 7.反转整数 题目 解题笔记 9.回文数 题目 解题笔记 13.罗马数字转整数 题目 解题笔记 14.最长公共前缀 题目 解题笔记 20.有效的括号 题 ...
- 算法初步---基本的数据结构(java为例)
最近搞算法,觉得超级吃力的,一直以为数学好的,数学可以考试满分,算法一定没什么问题,贱贱地,我发现我自己想多了,还是自己的基础薄弱吧,今天我来补补最基础的知识. 算法(Algorithm)是指解题方案 ...
- CNN:人工智能之神经网络算法进阶优化,六种不同优化算法实现手写数字识别逐步提高,应用案例自动驾驶之捕捉并识别周围车牌号—Jason niu
import mnist_loader from network3 import Network from network3 import ConvPoolLayer, FullyConnectedL ...
- NN:神经网络算法进阶优化法,进一步提高手写数字识别的准确率—Jason niu
上一篇文章,比较了三种算法实现对手写数字识别,其中,SVM和神经网络算法表现非常好准确率都在90%以上,本文章进一步探讨对神经网络算法优化,进一步提高准确率,通过测试发现,准确率提高了很多. 首先,改 ...
- Quartz.Net进阶之一:初识Job作业和触发器
前几天写了一篇有关Quartz.Net入门的文章,大家感觉不过瘾,想让我在写一些比较深入的文章.其实这个东西,我也是刚入门,我也想继续深入了解一下,所以就努力看了一些资料,然后自己再整理和翻译 ...
随机推荐
- SPI内容随笔
关于SPI的通信: SPI采用的是主从模式的同步通信,通过时钟来控制:一般情况下,使用双向全双工,收发的数据放在缓冲器FIFO中.数据的传输是主SPI的时钟在控制,从机是不能产生时钟的,如果没有时钟, ...
- 更换pip源到国内镜像
1.pip国内的一些镜像 阿里云 https://mirrors.aliyun.com/pypi/simple/ 中国科技大学 https://pypi.mirrors.ustc.edu.cn/ ...
- BTrace 初探
BTrace 是一款java诊断工具,在解决现场问题的时候非常有用. 今天使用的时候碰到几个坑,先记录一下. 下载下来以后直接运行报错 root@iZ2ze89756yjbvq7le6obdZ:~/b ...
- linux内核分析第六次实验
使用gdb跟踪创建新进程的过程 rm menu -rf git clone https://github.com/mengning/menu.git mv test_fork.c test.c 执 ...
- 网易云课堂-----Linux内核分析-----期末主观题
姚歌 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 下面是对8个课题的 ...
- [ERROR] Failed to execute goal org.codehaus.mojo:gwt-maven-plugin:2.5.0-rc1:compile (default) on project zeus-web: Command 解决
在编译maven项目,打包maven packeage -Dmaven.test.skip=TRUE时,报错“[ERROR] Failed to execute goal org.codehaus.m ...
- 集美大学1414-团队作业2:需求分析&原型设计分数发布
1.评分标准 检查项 分数 编号 调研文档或截图 1 1 软件需求分析说明书 2 2 NABCD 2 3 描述每个成员具体分工 1 4 原型设计 2 5 编码规范 1 6 推广视频 1 7 ...
- Jenkins Git Changelog Plugin
https://wiki.jenkins.io/display/JENKINS/Git+Changelog+Plugin
- [转帖]数据中心网络里的Underlay和Overlay
数据中心网络里的Underlay和Overlay https://blog.csdn.net/zjc801blog/article/details/54289683 2017年01月09日 15:47 ...
- HTTP协议整理
一.概念 1.HTTP协议:即超文本传输协议(Hypertext transfer protocol).是一种详细规定了浏览器和Web服务器之间互相通信的规则,它允许将超文本标记语言(HTML)文档从 ...