目录
1.寄包柜
题目
超市里有 n(1\le n\le10^5)n(1≤n≤105) 个寄包柜。每个寄包柜格子数量不一,第 ii 个寄包柜有 a_i(1\le a_i\le10^5)ai(1≤ai≤105) 个格子,不过我们并不知道各个 a_iai 的值。对于每个寄包柜,格子编号从 1 开始,一直到 a_iai。现在有 q(1 \le q\le10^5)q(1≤q≤105) 次操作:
1 i j k
:在第 ii 个柜子的第 jj 个格子存入物品 k(0\le k\le 10^9)k(0≤k≤109)。当 k=0k=0 时说明清空该格子。2 i j
:查询第 ii 个柜子的第 jj 个格子中的物品是什么,保证查询的柜子有存过东西。
已知超市里共计不会超过 10^7107 个寄包格子,a_iai 是确定然而未知的,但是保证一定不小于该柜子存物品请求的格子编号的最大值。当然也有可能某些寄包柜中一个格子都没有。
输入格式
第一行 2 个整数 nn 和 qq,寄包柜个数和询问次数。
接下来 qq 个整数,表示一次操作。
输出格式
对于查询操作时,输出答案,以换行隔开。
输入样例:
5 4
1 3 10000 118014
1 1 1 1
2 3 10000
2 1 1
输出样例:
118014
1
题解
map容器提供一对一的查找、排序功能,因此这道题确定用map容器。
但此时需要两个数据作为钥匙才能准确查找,因此map套娃:map<int,map<int,int>>直接来做。
代码
#include <bits/stdc++.h>
using namespace std;
map<int,map<int,int>> m; //map套map
int main(){
long long n ,q;
cin>>n>>q;
for(int i1 = 0;i1<q; i1++){
int b,i,j,k;
cin>>b>>i>>j;
if(b == 1){
cin>>k;
m[i][j] = k;
}
else{
cout<<m[i][j]<<endl;
}
}
return 0;
}
2.括号序列
题目
定义如下规则:
- 空串是「平衡括号序列」
- 若字符串 SS 是「平衡括号序列」,那么 \texttt{[}S\texttt][S] 和 \texttt{(}S\texttt)(S) 也都是「平衡括号序列」
- 若字符串 AA 和 BB 都是「平衡括号序列」,那么 ABAB(两字符串拼接起来)也是「平衡括号序列」。
例如,下面的字符串都是平衡括号序列:
()
,[]
,(())
,([])
,()[]
,()[()]
而以下几个则不是:
(
,[
,]
,)(
,())
,([()
现在,给定一个仅由 (
,)
,[
,]
构成的字符串 ss,请你按照如下的方式给字符串中每个字符配对:
- 从左到右扫描整个字符串。
- 对于当前的字符,如果它是一个右括号,考察它与它左侧离它最近的未匹配的的左括号。如果该括号与之对应(即小括号匹配小括号,中括号匹配中括号),则将二者配对。如果左侧未匹配的左括号不存在或与之不对应,则其配对失败。
配对结束后,对于 ss 中全部未配对的括号,请你在其旁边添加一个字符,使得该括号和新加的括号匹配。
输入格式
输入只有一行一个字符串,表示 ss。
输出格式
输出一行一个字符串表示你的答案。
输入输出样例:
输入 #1
([()
输出 #1
()[]()
输入 #2
([)
输出 #2
([])
说明/提示
数据规模与约定:对于全部的测试点,保证 ss 的长度不超过 100,且只含 (
,)
,[
,]
四个字符。
题解
首先遍历整个string,设置条件查找:1.合理的括号 2.不合理的括号。再遍历一遍,合理的括号直接输出,不合理的括号补全输出。
条件设置:设置一个新的整型数组,将其数值全部设成0。遍历string,当他是右括号时(即 ”)“ 和 ”]“),记录此时的下标i,并从i开始往回找。如果在i之前能找到没有被标记的、匹配的左括号(即 "(“ 和 ”[” )则两个都标记。遍历过后,标记的都是合理的,未标记的都是不合理的。
代码
#include <bits/stdc++.h>
using namespace std;
int a[105];//设置标记的数组,此时默认数组内全是0。
int main(){
string s;
cin>>s;
for(int i = 0;i<s.length();i++){
if(s[i] == ')'){
for(int j = i-1;j >= 0;j--){
if(s[j] == '(' && a[j] == 0) {
a[i] = 1;//标记合理的右括号
a[j] = 1;//标记合理的左括号
break;
}
else if (s[j] == '[' && a[j] == 0) break;
}
}
//同理
else if(s[i] == ']'){
for(int j = i-1;j >= 0;j--){
if(s[j] == '['&& a[j] == 0) {
a[i] = 1;
a[j] = 1;
break;
}
else if (s[j] == '(' && a[j] == 0) break;
}
}
}
for(int i = 0;i<s.length();i++){
if(a[i] == 1) cout<<s[i];//合理的直接输出
else{
//不合理的补全输出
if(s[i] == '(' || s[i] == ')') cout<<"()";
else cout<<"[]";
}
}
return 0;
}
3.后缀表达式
题目
所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。
如:\texttt{3*(5-2)+7}3*(5-2)+7 对应的后缀表达式为:\texttt{3.5.2.-*7.+@}3.5.2.-*7.+@。在该式中,@
为表达式的结束符号。.
为操作数的结束符号。
输入格式
输入一行一个字符串 ss,表示后缀表达式。
输出格式
输出一个整数,表示表达式的值。
输入输出样例
输入 #1
3.5.2.-*7.+@
输出 #1
16
说明/提示
数据保证,1 \leq |s| \leq 501≤∣s∣≤50,答案和计算过程中的每一个值的绝对值不超过 10^9109。
题解
一看就要用stack。
输入一个string,在这个string中,“@”是整个表达式的终止符号,“+”、“-”、“*”、“/”任意一个是stack的终止入栈的标志。因此整个过程就是:数字存入栈,遇到符号停止,并从栈顶取数字计算。继续存入数字,继续计算,直到遇到“@”。
以上就是代码运行全过程。
代码
#include <bits/stdc++.h>
using namespace std;
stack<int> st;//建立栈
int x,y;
int main(){
string str;
cin>>str;
int a = 0;
for(int i = 0; str[i] != '@' ; i++){
if(str[i] <= '9' && str[i] >= '0'){
a = a * 10 + (str[i] - '0');//存入数字(很多位)
}
else if(str[i] == '.'){
st.push(a);//遇到“.” 入栈
a = 0;
}
else if(str[i] == '+' || str[i] == '-'||str[i] == '*'||str[i] == '/'){
x = st.top();
st.pop();
y = st.top();
st.pop();
//取出栈顶的两位数
if(str[i] == '+') st.push(x+y);//运算结果要重新入栈
else if(str[i] == '-') st.push(y-x);
else if(str[i] == '*') st.push(x*y);
else if(str[i] == '/') st.push(y/x);
}
}
cout<<st.top();
return 0;
}
4.队列安排
题目
一个学校里老师要将班上 NN 个同学排成一列,同学被编号为 1\sim N1∼N,他采取如下的方法:
-
先将 11 号同学安排进队列,这时队列中只有他一个人;
-
2-N2−N 号同学依次入列,编号为 ii 的同学入列方式为:老师指定编号为 ii 的同学站在编号为 1\sim(i-1)1∼(i−1) 中某位同学(即之前已经入列的同学)的左边或右边;
-
从队列中去掉 M(M<N)M(M<N) 个同学,其他同学位置顺序不变。
在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。
输入格式
第 11 行为一个正整数 NN,表示了有 NN 个同学。
第 2\sim N2∼N行,第 ii 行包含两个整数 k,pk,p,其中 kk 为小于 ii 的正整数,pp 为 00 或者 11。若 pp 为00,则表示将 ii 号同学插入到 kk 号同学的左边,pp 为 11 则表示插入到右边。
第 N+1N+1 行为一个正整数 MM,表示去掉的同学数目。
接下来 MM 行,每行一个正整数 xx,表示将 xx 号同学从队列中移去,如果 xx 号同学已经不在队列中则忽略这一条指令。
输出格式
11 行,包含最多 NN 个空格隔开的正整数,表示了队列从左到右所有同学的编号,行末换行且无空格。
输入输出样例
输入 #1
4 1 0 2 1 1 0 2 3 3
输出 #1
2 4 1
说明/提示
样例解释:
将同学 22 插入至同学 11 左边,此时队列为:
2 1
将同学 33 插入至同学 22 右边,此时队列为:
2 3 1
将同学 44 插入至同学 11 左边,此时队列为:
2 3 4 1
将同学 33 从队列中移出,此时队列为:
2 4 1
同学 33 已经不在队列中,忽略最后一条指令
最终队列:
2 4 1
数据范围
对于 20\%20% 的数据,有 1\leq N\leq 101≤N≤10;
对于 40\%40% 的数据,有 1\leq N\leq 10001≤N≤1000;
对于 100\%100% 的数据,有 1\leq N,M\leq1000001≤N,M≤100000。
题解
有“插入”和“删除”,确定用链表——list。
初始有一个1号同学,在list中直接加入数字“1”。到之后读入两个数据,x号同学的左边/右边。每一次插入同学,都先遍历list,找到x的迭代器。如果在x的左边,则迭代器不变。如果在x的右边,则迭代器后退一位。完成插入同学。
删除是根据list中的数值来确定删除谁,因此调用自带的remove()函数,直接删除。(但是会超时)
插入和删除完毕,输出list。
代码
#include <bits/stdc++.h>
using namespace std;
list<int> v;
list<int>::iterator it;
void print(list<int> v){
list<int>::iterator it2 = v.begin();
list<int>::iterator it3 = v.end();
it3--;
for(;it2 != it3;it2++){
cout << ( *it2 ) << " ";
}
cout<<(*it3);//最后不能有空格
}
int main(){
int n,m;
cin>>n;
v.push_back(1);//初始时已经有一位同学在里面
for(int i = 2;i<=n;i++){
//插入
int x,b;
cin>>x>>b;
for(list<int>::iterator it1 = v.begin(); it1 != v.end(); it1++){
if((*it1) == x){ //寻找标号为x的
if(b == 1) it1++;//b=1 为往x号的右边插入 迭代器往后移动一位
//若要往x左边插入 迭代器不变
v.insert(it1,i);
break;
}
}
}
//删除
cin>>m;
for(int i = 0;i<m; i++){
int x;
cin>>x;
v.remove(x);//STL中的list容器提供数值删除的方法函数 直接用
}
print(v);
return 0;
}