[算法进阶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入门的文章,大家感觉不过瘾,想让我在写一些比较深入的文章.其实这个东西,我也是刚入门,我也想继续深入了解一下,所以就努力看了一些资料,然后自己再整理和翻译 ...
随机推荐
- Ionic 添加java原生代码 报support.v4不存在问题
在做Ionic Hybird app开发过程中不可避免的使用一些原生代码的问题,那么怎么添加原生代码呢? 答案很简单:1.将原生代码直接拷贝到项目下的 你的项目名/platforms/android/ ...
- python语言程序设计5
1, 评估函数eval() 去掉参数最外侧引号并执行余下语句的函数. 比如eval("1"),经过运行可以得到数字 1 去得是单双引号,不是括号哦.. 广泛来说,能将任何字符串的形 ...
- html5录音支持pc和Android、ios部分浏览器,微信也是支持的,JavaScript getUserMedia
以前在前人基础上重复造了一个网页录音的轮子,顺带把github仓库使用研究了一下,扔到了github上. 优势在于结构简单,可插拔式的录音格式支持,几乎可以支持任意格式(前提有相应的编码器):默认提供 ...
- CentOS搭建NAT和DHCP服务,实现共享上网
什么是NAT? NAT(Network address translation)即网络地址转换,作为一种过渡解决手段,可以用来减少对全球合法IP地址的需求.简单的说,NAT就是在内部专用网络中使用内部 ...
- Docker容器学习梳理 - 容器间网络通信设置(Pipework和Open vSwitch)
自从Docker容器出现以来,容器的网络通信就一直是被关注的焦点,也是生产环境的迫切需求.容器的网络通信又可以分为两大方面:单主机容器上的相互通信,和跨主机的容器相互通信.下面将分别针对这两方面,对容 ...
- part 1
注意:本次源码分析选择2.0.3(因为不支持IE6.7.8,就少了很多兼容的hack的写法,对了解jQuery的实现原理有很大的帮助) 1.jQuery有不同的版本,从2.x版本便不再支持IE6.7. ...
- javaScript——DOM1级,DOM2级,DOM3级
DOM0,DOM2,DOM3事件处理方式区别:http://www.qdfuns.com/notes/11861/e21736a0b15bceca0dc7f76d77c2fb5a.html JS中do ...
- tmux使用总结
ctrl+b +%:增加垂直分屏 ctlr+b +左右箭头: 在垂直分屏中移动 ctrl+b+c:新建窗口(不分屏) ctrl+b+数字键: 切换窗口 ctrl+b+d: 断开窗口 tmux a : ...
- C. Books Queries
链接 [http://codeforces.com/contest/1066/problem/C] 题意 开始空队列,可以进行前插和后插,还可以查询使某个数的为最左或最右需要去掉的最少数字 分析 模拟 ...
- 广商博客沖刺第一天(new ver):
項目名稱:廣商博客 沖刺二天傳送門 此次Sprint的目标:全部sprint任務完成 时间:1星期左右 每日立会 Daily Standup Meeting: 1#A3008 晚上8点开始,大概1小时 ...