【深基15.例2】寄包柜
超市里有n(1≤n≤10^5) 个寄包柜。每个寄包柜格子数量不一,第 i 个寄包柜有ai(1≤ai≤10^5) 个格子,不过我们并不知道各个 ai 的值。对于每个寄包柜,格子编号从 1 开始,一直到 ai。现q(1≤q≤105) 次操作:
1 i j k
:在第 i 个柜子的第 j 个格子存入物品 k(0≤k≤109)。当k=0 时说明清空该格子。2 i j
:查询第 i 个柜子的第 j 个格子中的物品是什么,保证查询的柜子有存过东西。
已知超市里共计不会超过 10^7 个寄包格子,ai 是确定然而未知的,但是保证一定不小于该柜子存物品请求的格子编号的最大值。当然也有可能某些寄包柜中一个格子都没有。
输入格式
第一行 2 个整数 n 和 q,寄包柜个数和询问次数。
接下来 q 个整数,表示一次操作。
输出格式
对于查询操作时,输出答案,以换行隔开。
输入输出样例
输入 #1
5 4 1 3 10000 118014 1 1 1 1 2 3 10000 2 1 1
输出 #1
118014 1
本题由于数据较大,使用二维数组必然造成内存溢出,为了节约内存,这里使用链表
#include<iostream>
using namespace std;
long long n,i,j,k,q,num=1;
const int maxn=1e5+5;
int main()
{
struct save_container//该结构体用于存储物品相关信息
{
int i;//i号柜子
int j;//第j个格子
int value;//存储的内容
int r;//l和r分别为该数据左/右侧内容
int l;
}s[maxn]={0,0,0,0,0};
cin>>n>>q;//输入
for(int y=1;y<=q;y++)
{
cin>>n;
if(n-1)//n为2时,进行查询操作
{
cin>>i>>j;
for(int u=s[0].r;u;u=s[u].r)
{
if((s[u].i==i)&&(s[u].j==j))
{
cout<<s[u].value<<endl;
break;
}
}
}
else//n为1时,进行存储
{
cin>>i>>j>>k;
if(!k)//k为0时删除
{
for(int u=s[0].r;u;u=s[u].r)//寻找目标
{
if((s[u].i==i)&&(s[u].j==j))
{
s[s[u].l].r=s[u].r;//删除
s[s[u].r].l=s[u].l;
s[u].r=s[u].l=0;
break;
}
}
}
else//k不为0时将数据插入链表右端
{
s[num].i=i;
s[num].j=j;
s[num].value=k;
s[num].r=num+1;
s[s[num].l].r=num;
s[s[num].r].l=num;
num++;
}
}
}
return 0;
}
P1241 括号序列
题目描述
定义如下规则:
- 空串是「平衡括号序列」
- 若字符串 S 是「平衡括号序列」,那么 [S] 和 (S) 也都是「平衡括号序列」
- 若字符串 A 和 B 都是「平衡括号序列」,那么 ABAB(两字符串拼接起来)也是「平衡括号序列」。
例如,下面的字符串都是平衡括号序列:
()
,[]
,(())
,([])
,()[]
,()[()]
而以下几个则不是:
(
,[
,]
,)(
,())
,([()
现在,给定一个仅由 (
,)
,[
,]
构成的字符串 ss,请你按照如下的方式给字符串中每个字符配对:
- 从左到右扫描整个字符串。
- 对于当前的字符,如果它是一个右括号,考察它与它左侧离它最近的未匹配的的左括号。如果该括号与之对应(即小括号匹配小括号,中括号匹配中括号),则将二者配对。如果左侧未匹配的左括号不存在或与之不对应,则其配对失败。
配对结束后,对于 s中全部未配对的括号,请你在其旁边添加一个字符,使得该括号和新加的括号匹配。
输入格式
输入只有一行一个字符串,表示 s。
输出格式
输出一行一个字符串表示你的答案。
输入输出样例
输入 #1复制
([()
输出 #1复制
()[]()
输入 #2复制
([)
输出 #2复制
()[]()
说明/提示
数据规模与约定
对于全部的测试点,保证 ss 的长度不超过 100,且只含 (
,)
,[
,]
四个字符。
#include<iostream>
using namespace std;
int top=0,i=0;
struct kuohao
{
char a;
int i;
}c[1111]={'0',0},C[1111];//结构体数组c(小写)用于记录所有的括号数据(a记录括号种类,i记录是否配对)。结构体数组C(大写)用于记录所有的左括号数据(a记录括号种类,i记录该括号次序)。
int main()
{
while(cin>>c[i].a)//输入括号
{
if((c[i].a=='(')||(c[i].a=='['))//将左括号存入栈C中
{
C[top].a=c[i].a;
C[top].i=i;
top++;//栈顶加一
}
else
{
if(((c[i].a==')')&&(C[top-1].a=='('))||((c[i].a==']')&&(C[top-1].a=='[')))
{
c[i].i=1;
c[C[top-1].i].i=1;//当右括号与栈C顶部括号匹配时,将配对的两个括号标记为已配对(对应i改为1)
top--;//栈顶减一
}
}
i++;
}
for(int j=0;j<=i;j++)//输出
{
if(c[j].i==1)
{
cout<<c[j].a;//i为1时表示已配对,直接输出
}
else
{
if((c[j].a=='[')||(c[j].a==']'))//未配对的补齐后输出
{
cout<<"[]";
}
else if((c[j].a=='(')||(c[j].a==')'))
{
cout<<"()";
}
}
}
return 0;
}
P1449 后缀表达式
题目描述
所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。
如:3*(5-2)+7 对应的后缀表达式为:3.5.2.-*7.+@。在该式中,@
为表达式的结束符号。.
为操作数的结束符号。
输入格式
输入一行一个字符串 s,表示后缀表达式。
输出格式
输出一个整数,表示表达式的值。
输入输出样例
输入 #1
3.5.2.-*7.+@
输出 #1
16
说明/提示
数据保证,1≤∣s∣≤50,答案和计算过程中的每一个值的绝对值不超过 10^9。
#include<iostream>
#include<string>
#include<cmath>
using namespace std;
const long long maxn=1e5+5;
string t="0";
char ch;
long long sta[maxn],top;//用栈存储数字,每次计算时使用顶部的两个数字
long long num(string a)//该函数用于将字符串类型数字转化为lonng long类型的数字
{
int ans=0;
for(int i=0;i<a.size();i++)
{
ans+=((int)a[i]-(int)'0')*pow(10,a.size()-1-i);
}
return ans;
}
int main()
{
while(cin>>ch)
{
if(ch<=(int)'9'&&ch>=(int)'0')
{
if(t=="0")
{
t[0]=ch;
}
else
{
t=t+ch;
}
}
else if(ch=='.')
{
sta[top]=num(t);
top++;
t="0";
}
else if(ch=='@')//结束
{
cout<<sta[0];
break;
}
else//计算
{
top--;
if(ch=='+')
{
sta[top-1]+=sta[top];
}
else if(ch=='-')
{
sta[top-1]-=sta[top];
}
else if(ch=='*')
{
sta[top-1]*=sta[top];
}
else if(ch=='/')
{
sta[top-1]/=sta[top];
}
}
}
return 0;
}
P1160 队列安排
题目描述
一个学校里老师要将班上 N 个同学排成一列,同学被编号为 1∼N,他采取如下的方法:
-
先将 1 号同学安排进队列,这时队列中只有他一个人;
-
2−N 号同学依次入列,编号为 i 的同学入列方式为:老师指定编号为 i 的同学站在编号为 1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;
-
从队列中去掉 M(M<N) 个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第 11 行为一个正整数 N,表示了有 N 个同学。
第 2∼N行,第i行包含两个整数 k,p,其中 k 为小于 i 的正整数,p 为 0 或者 1。若 p 为0,则表示将 i 号同学插入到 k 号同学的左边,p 为 1 则表示插入到右边。
第N+1 行为一个正整数 M,表示去掉的同学数目。
接下来 M 行,每行一个正整数 x,表示将 x 号同学从队列中移去,如果 x 号同学已经不在队列中则忽略这一条指令。
输出格式
1 行,包含最多 N 个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
输入输出样例
输入 #1
4 1 0 2 1 1 0 2 3 3
输出 #1
2 4 1
说明/提示
样例解释:
将同学 2 插入至同学 1 左边,此时队列为:
2 1
将同学 3 插入至同学 2 右边,此时队列为:
2 3 1
将同学 4 插入至同学 1 左边,此时队列为:
2 3 4 1
将同学 3 从队列中移出,此时队列为:
2 4 1
同学 3 已经不在队列中,忽略最后一条指令
最终队列:
2 4 1
数据范围
对于 20% 的数据,有 1≤N≤10;
对于40% 的数据,有 1≤N≤1000;
对于 100% 的数据,有 1≤N,M≤100000。
#include<iostream>
using namespace std;
int N,nn,k,p,n=1;
struct stu_quene//创建双向链表,a用于标记学生是否被移除
{
int l;
int r;
int a;
}stu[100005]={0,0,0};
int main()
{
stu[0].l=1;
stu[0].r=1;
stu[1].r=0;//首先将第一个学生插入链表,一号学生和0号学生“面对面手挽手”
stu[1].l=0;//0号学生事实上不存在,用于判断链表的结束
cin>>N;
for(int i=2;i<=N;i++)
{
cin>>k>>p;
n++;
if(p)//插入左边
{
stu[n].l=k;
stu[n].r=stu[k].r;
stu[stu[k].r].l=n;
stu[k].r=n;
}
else//插入右边
{
stu[n].r=k;
stu[n].l=stu[k].l;
stu[stu[k].l].r=n;
stu[k].l=n;
}
}
cin>>nn;//输入需要移除学生的数量
for(int i=1;i<=nn;i++)
{
cin>>k;
stu[k].a=1;//将被移除学生的a标记为1
}
for(int i=stu[0].r;i;i=stu[i].r)//从0号学生开始,向右遍历链表,回到0号时结束
{
if(stu[i].a)
{
continue;
}
cout<<i<<" ";
}
}