week3

1-1题目描述

超市里有 n(1≤n≤105) 个寄包柜。每个寄包柜格子数量不一,第 i个寄包柜有 a_i(1≤a_i*≤10^5) 个格子,不过我们并不知道各个 a_i 的值。对于每个寄包柜,格子编号从 1 开始,一直到 a_i。现在有 q(1≤q≤10^5) 次操作:

  • 1 i j k:在第 i 个柜子的第 j 个格子存入物品 k(0≤k≤10^9)。当 k=0 时说明清空该格子。

  • 2 i j:查询第 i个柜子的第 j 个格子中的物品是什么,保证查询的柜子有存过东西。

已知超市里共计不会超过 10^7个寄包格子,a_i 是确定然而未知的,但是保证一定不小于该柜子存物品请求的格子编号的最大值。当然也有可能某些寄包柜中一个格子都没有。

输入格式

第一行 2 个整数 n 和 q,寄包柜个数和询问次数。

接下来 q 个整数,表示一次操作。

输出格式

对于查询操作时,输出答案,以换行隔开。

输入输出样例

输入 #1复制

5 4
1 3 10000 118014
1 1 1 1
2 3 10000
2 1 1

输出 #1复制

118014
1

说明/提示

\text{upd 2022.7.26}upd 2022.7.26:新增加一组 Hack 数据。

解题思路:构建一个二维map函数,表示第i个柜子的第j个格子

完整代码如下:

#include <bits/stdc++.h>
using namespace std;
​
const int maxn=1e5+5;
​
map<int,map<int,int> > m; //等价map<int,int> m[maxn]
                          // 对二维map函数的构建 
​
int main()
{
    int n,q;
    cin>>n>>q;
    int x,y,z,t;
    while(q--){
        cin>>t;
        if(t==1){
            cin>>x>>y>>z;
            m[x][y]=z; //直接将物品存入指定位置 
        }else{
            cin>>x>>y;
            cout<<m[x][y]<<endl;
        } //访问指定位置,输出物品数量 
    }
    return 0;
}
​

1-2题目描述

定义如下规则:

  1. 空串是「平衡括号序列」

  2. 若字符串 S 是「平衡括号序列」,那么 [S]和 {S} 也都是「平衡括号序列」

  3. 若字符串 A 和 B 都是「平衡括号序列」,那么 AB(两字符串拼接起来)也是「平衡括号序列」。

例如,下面的字符串都是平衡括号序列:

()[](())([])()[]()[()]

而以下几个则不是:

([])(())([()

现在,给定一个仅由 ()[]构成的字符串 $s$,请你按照如下的方式给字符串中每个字符配对:

  1. 从左到右扫描整个字符串。

  2. 对于当前的字符,如果它是一个右括号,考察它与它左侧离它最近未匹配的的左括号。如果该括号与之对应(即小括号匹配小括号,中括号匹配中括号),则将二者配对。如果左侧未匹配的左括号不存在或与之不对应,则其配对失败。

配对结束后,对于 s 中全部未配对的括号,请你在其旁边添加一个字符,使得该括号和新加的括号匹配。

输入格式

输入只有一行一个字符串,表示 s

输出格式

输出一行一个字符串表示你的答案。

样例 #1

样例输入 #1

([()

样例输出 #1

()[]()

样例 #2

样例输入 #2

([)

样例输出 #2

()[]()

提示

数据规模与约定

对于全部的测试点,保证 s 的长度不超过 100,且只含 ()[] 四个字符。

解题思路:栈

先遍历字符串s,如果碰到左括号,存入栈中,并在b数组中存入它的匹配号,

如果碰到右括号,

判断栈内是否有东西:

1无 在b数组中存入它的匹配号

2有,

则判断栈顶是否有与其匹配的左括号:

1有 弹栈、对b数组相应位置(右括号,匹配的左括号)进行标记

2无 在b数组中存入它的匹配号

输出:对于b[i]中标记的,输出相应的s[i]

b[i]数组中有左括号的,先输出b[i]再输出s[i]

不然先输出s[i]再输出b[i]

注意:=和==一定要分清楚(别问我是怎么知道的qwq

完整代码如下:

#include <bits/stdc++.h>
using namespace std;
​
char s[105],b[105];
stack<int> m; //建立一个栈 
​
int main()
{
    cin>>s;
    int len=strlen(s);
    for(int i=0; i<len; i++){
        if(s[i]=='('){
            m.push(i);
            b[i]=')';
            continue;
        }
        if(s[i]=='['){
            m.push(i);
            b[i]=']';
            continue;
        }  //对左括号的处理 
      if(m.empty()|| s[i]==')' && s[m.top()]=='[' || s[i]==']' && s[m.top()]=='('){
            if(s[i]==']') b[i]='[';
            else b[i]='('; 
        }else{
            b[m.top()]=' ';
            b[i]=' ';
            m.pop();
        } //对右括号的处理 
    }  
    for(int i=0; i<len; i++){       
        if(b[i]==' ') cout<<s[i];
        else if(b[i]=='[' || b[i]=='(') cout<<b[i]<<s[i];
        else cout<<s[i]<<b[i];
    }
    return 0;
}
​

1-3题目描述

所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。

如:3(5-2)+7 对应的后缀表达式为3.5.2.-7.+@在该式中,@ 为表达式的结束符号。. 为操作数的结束符号。

输入格式

输入一行一个字符串 s,表示后缀表达式。

输出格式

输出一个整数,表示表达式的值。

样例 #1

样例输入 #1

3.5.2.-*7.+@

样例输出 #1

16

提示

数据保证,1 <=|s|<= 50,答案和计算过程中的每一个值的绝对值不超过 10^9。

解题思路:以字符串的形式输入

碰到".",将前面的数字存入栈中

碰到运算符,取出栈顶的俩个数进行运算,再把结果存入栈中

最后栈中留下的那个数就是答案

完整代码:

#include <bits/stdc++.h>
using namespace std;
​
stack<int> m;
​
int main()
{
    char c,s[10005];
    int k=0;
    while((c=getchar())!='@'){
        s[k++]=c;       
    }
    int len=strlen(s);
    int sum=0,cnt,t1,t2;
    for(int i=0; i<len; i++){
        
        if(s[i]>='0' && s[i]<='9'){
            sum=sum*10+(s[i]-'0');
        }//将字符串转化为数字 
        if(s[i]=='.'){
        m.push(sum);
        sum=0;
        }//存入栈 
        if(s[i]=='+'){
            t1=m.top();
            m.pop();
            t2=m.top();
            m.pop();
            cnt=t1+t2;
            m.push(cnt);
        }
        if(s[i]=='-'){
            t1=m.top();
            m.pop();
            t2=m.top();
            m.pop();
            cnt=t2-t1;
            m.push(cnt);
        }
        if(s[i]=='*'){
            t1=m.top();
            m.pop();
            t2=m.top();
            m.pop();
            cnt=t1*t2;
            m.push(cnt);
        }
        if(s[i]=='/'){
            t1=m.top();
            m.pop();
            t2=m.top();
            m.pop(); 
            cnt=t2/t1;
            m.push(cnt);
        }
    }//进行运算 
    cout<<m.top();
    return 0;
}
​

1-4题目描述

一个学校里老师要将班上 N 个同学排成一列,同学被编号为 1~N,他采取如下的方法:

  1. 先将 1 号同学安排进队列,这时队列中只有他一个人;

  2. 2~N 号同学依次入列,编号为 i 的同学入列方式为:老师指定编号为 i 的同学站在编号为 1~(i-1)中某位同学(即之前已经入列的同学)的左边或右边;

  3. 从队列中去掉 M(M<N) 个同学,其他同学位置顺序不变。

在所有同学按照上述方法队列排列完毕后,老师想知道从左到右所有同学的编号。

输入格式

第 1 行为一个正整数 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

样例输入 #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。

解题思路:双向链表(此处用数组模拟)

初始化:从零节点开始

插入:假设将k插入i的右边(拿小盆友手牵手做比方) 最后形成i,k,j

先将k的左手牵i,k的右手牵i的右手原来牵的人

再i的右手牵k,k的右手牵的人的左手牵k

插入i的左边同理

移除:标记要移除的人

输出:for(int i=a[0].r;i;i=a[i].r)

从零节点的右开始到零节点结束

完整代码如下:

#include <bits/stdc++.h>
using namespace std;
​
const int maxn=1e5+5;
​
struct stu{
    int l,r;
    int d;//标记是否输出 
}a[maxn]={0};
​
void add(int i,int k,int p);
​
int main()
{   
    a[0].r=0,a[0].l=0;
    add(1,0,1);//链的初始化 
    int n;
    cin>>n;
    int k,p;
    for(int i=2; i<=n; i++){
        cin>>k>>p;
        add(i,k,p);//新增的同学 
    }
    int m,x;
    cin>>m;
    while(m--){
        cin>>x;
        a[x].d=1;
    } //删除的同学 
    for(int i=a[0].r;i;i=a[i].r){
        if(a[i].d==0) cout<<i<<" ";
    }
    return 0;
}
​
void add(int i,int k,int p)
{
    if(p==0){          //插左 
        a[i].l=a[k].l;
        a[i].r=k;
        a[k].l=i;
        a[a[i].l].r=i;
    }else{             //插右 
        a[i].l=k;
        a[i].r=a[k].r;
        a[k].r=i;
        a[a[i].r].l=i;
    }
}
​

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值