这周说实话学习量非常的大,也可能是我太菜了 /(ㄒoㄒ)/~~
做测评我只做最真的
第一题
洛谷
P3613 【深基15.例2】寄包柜
题目描述
超市里有 n(1<= n<=10^5)个寄包柜。每个寄包柜格子数量不一,第 i 个寄包柜有 ai(1≤ai≤10^5) 个格子,不过我们并不知道各个 ai 的值。对于每个寄包柜,格子编号从 1 开始,一直到 ai。现在有 q(1<= q<=10^5)次操作:
1 i j k
:在第 ii 个柜子的第 jj 个格子存入物品 k(0≤k≤10^9)。当 k=0k=0 时说明清空该格子。2 i j
:查询第 ii 个柜子的第 jj 个格子中的物品是什么,保证查询的柜子有存过东西。
已知超市里共计不会超过 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
面对这题,审完题之后发现,题目的意思就是
有n个柜子,柜子里面还有格子
一开始我们就可能会想到二维数组a[n][m] n个柜子,柜子里面m个格子里面储存不同的值
但是这样的话我们就得定义一个10^5 * 10^5 的二维数组,太大了
这时候我们想到map,stl里面的一个容器
map可以储存一个键值对,那我们一个柜子格子(键)对应一个物品(值)
对于两个数据构成的一个数据,我们可以用pair来储存
所以我们采用map<pair<>,int> 来对这题进行解决
pair
pair可以把两个数据合成为一个数据,pair<数据类型1,数据类型2> p(v1,v2)创建一个pair里面对应的元素分别为v1,v2;可以用pair.first来访问v1,用pair.second来访问v2;
也可以用pair<v1的数据类型,v2的数据类型> p1(p)把p里面的数据拷贝给p1;
map
map使用map<数据类型1,数据类型2> 变量名来定义
map<char,int> mp 通过mp['c']=20;先定义一个mp的map数据,再把mp里面的char赋值为c,int赋值为20;通过键来获取这个键所对应的值,或者通过mp->first来获取键变量,通过mp->second获取值变量
代码实现如下
#include <bits/stdc++.h>
#include <map>
using namespace std;
int main(){
int n,q,a,c,d,e;
cin>>n>>q;
map<pair<int,int>,int> b;
for(int i=1;i<=q;i++){
cin>>a>>c>>d;
if(a==1){
cin>>e;
b[{c,d}]=e;
}
else{
cout<<b[{c,d}]<<endl;
}
}
}
第二题,有点折磨人的一题
洛谷P1241 括号序列
题目描述
定义如下规则:
- 空串是「平衡括号序列」
- 若字符串 S 是「平衡括号序列」,那么 [S] 和 (S) 也都是「平衡括号序列」
- 若字符串 A 和 B 都是「平衡括号序列」,那么 AB(两字符串拼接起来)也是「平衡括号序列」。
例如,下面的字符串都是平衡括号序列:
()
,[]
,(())
,([])
,()[]
,()[()]
而以下几个则不是:
(
,[
,]
,)(
,())
,([()
现在,给定一个仅由 (
,)
,[
,]
构成的字符串 s,请你按照如下的方式给字符串中每个字符配对:
- 从左到右扫描整个字符串。
- 对于当前的字符,如果它是一个右括号,考察它与它左侧离它最近的未匹配的的左括号。如果该括号与之对应(即小括号匹配小括号,中括号匹配中括号),则将二者配对。如果左侧未匹配的左括号不存在或与之不对应,则其配对失败。
配对结束后,对于 s 中全部未配对的括号,请你在其旁边添加一个字符,使得该括号和新加的括号匹配。
输入格式
输入只有一行一个字符串,表示 s。
输出格式
输出一行一个字符串表示你的答案。
输入输出样例
输入 #1
([()
输出 #1
()[]()
输入 #2
([)
输出 #2
()[]()
说明/提示
数据规模与约定
对于全部的测试点,保证 ss 的长度不超过 100,且只含 (
,)
,[
,]
四个字符。
通过题意,我们可以知道,我们就是要去找一个右括号)]它能找到的最近的左括号,如果这个左括号没有匹配成功且能和这个右括号匹配,那这两个括号我们就标记为匹配成功
例如([)] 对于第一个出现的右括号)来说,它左边第一个左括号是[找到了它,但是二者不可以匹配,那么这一对匹配不成功,于是我们就帮他补齐([()]对于下一个右括号]找到它左边第一个左括号(它现在是匹配成功的那么下一个[这个是未匹配的,能和]匹配,所以他们两走在了一起判断完了检查一下这个字符串第一个(还是单身的,那我们帮他找一个伴侣,所以匹配完是()[()]
那我们该怎么办,一个个的去检查然后标记这个括号是否匹配成功,然后遍历找第一个未匹配成功的左括号,然后再遍历字符串找出没有匹配成功的左括号给他补齐
#include <bits/stdc++.h>
using namespace std;
char p[101];
int jl[101],top;
int main()
{
string s;
cin>>s;
int a=s.length();
for(int i=0;i<a;i++){
if(s[i]=='(') jl[++top]=i,p[i]=')';//左括号我们记录下这个括号的位置 再帮他配对
else if(s[i]=='[') jl[++top]=i,p[i]=']';
else if(s[i]==')'||s[i]==']'){//右括号我们进行匹配 找到第一个左括号
if(!top||p[jl[top]]!=s[i]){//右括号是第一个或者没有找到匹配的
if(s[i]==')') p[i]='(';
else p[i]='[';//用p来补全不能匹配的括号
}
else p[jl[top--]]=' ';//能匹配到左括号,把这个左括号对应的右括号删去
}
}
for(int i=0;i<a;i++){
if(p[i]=='['||p[i]=='(') cout<<p[i];
cout<<s[i];
if(p[i]==']'||p[i]==')') cout<<p[i];
}
}
这边我们先帮他一个个配对好了,对应在字符数组p里面,如果有配对成功的,那我们就把字符数组p里面对应的括号删除,就形成了一个p与输入字符串s互补的一个完整答案
这边我们得注意一个特殊的例子,就是)和]在字符串首位置的时候中特殊条件
输出先输出p里面的[和(,因为字符串第一个字符可能就是)或],然后输出字符串,在输出p里面的]和),这样就可以 省略掉遍历字符串再去寻找未匹配的括号的操作了
洛谷P1449 后缀表达式
题目描述
所谓后缀表达式是指这样的一个表达式:式中不再引用括号,运算符号放在两个运算对象之后,所有计算按运算符号出现的顺序,严格地由左而右新进行(不用考虑运算符的优先级)。
如:\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≤∣s∣≤50,答案和计算过程中的每一个值的绝对值不超过 10^9。
怎么说,就是一个.对应一个运算符和@,一个字符串,遇到@就结束,那我们完全可以改成一个字符数组一直输入直到输入的数据为@时停止;
然后运算一直是两个数进行运算,那我们就可以定义一个数组来储存数字然后再慢慢地往回加进行i--数组往前读取;
例如上面,就是第一个输入的运算符-对它前面的两个
5,2得到数字3然后再找到下一个运算符*,3*3得到9,在下一个运算符+得到9+7得到最终值16
那我们就可以开始写代码了
#include <bits/stdc++.h>
using namespace std;
long long sum[1005];
int main()
{
char s;
long long i=0,a=0;
while((s=getchar())!='@'){
if(s>='0' && s<='9')
{
a*=10;
a+=s-'0';
}
else if(s=='.'){
i++;
sum[i]=a;
a=0;
}
else if(s=='-'){
sum[i-1]=sum[i-1]-sum[i];
sum[i]=0;
i--;
}
else if(s=='+'){
sum[i-1]=sum[i-1]+sum[i];
sum[i]=0;
i--;
}
else if(s=='*'){
sum[i-1]=sum[i-1]*sum[i];
sum[i]=0;
i--;
}
else if(s=='/'){
sum[i-1]=sum[i-1]/sum[i];
sum[i]=0;
i--;
}
}
cout<<sum[1];
return 0;
}
题目描述
一个学校里老师要将班上 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
说明/提示
样例解释:
将同学 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。
解释的很清楚了,那我们得对学生进行分析,因为是要插入和删除的,那我们首先想到链表,
链表就能进行插入和删除,链表结构体数组的索引表示学生的学号,在链表内定义一个resist来确定这个学生是否插入到链表内或者是否被删除,输出时我们就按照链表的顺序进行输出,一个接一个地输出,这边使用的是双向链表来实现这个功能
for(int i=a[0].r;i;i=a[i].r){
if(a[i].resist==0) cout<<i<<' ';
}
用这段代码来实现链表的对应的索引一个一个地准确输出
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m;
struct T{
int l,r;
int resist;
}a[maxn]={0};
void add(int i,int p,int f){//i是新增的同学 **顺序不能乱,乱了就会出错
if(f==1){//i插入在p右边
a[i].l=p;
a[i].r=a[p].r;
a[a[i].r].l=i;
a[p].r=i;
}//实现在p和p右边的位置之间插入一个i
else{//i插入在p的左边
a[i].r=p;
a[i].l=a[p].l;
a[a[i].l].r=i;
a[p].l=i;
}
}
int main(){
int p,f,b;
cin>>n;
a[0].l=0,a[0].r=0;//重置第一位同学,假设第一位同学插入在第0的同学的旁边
add(1,0,1);
for(int i=2;i<=n;i++){//0表示左边,1表示右边用f来记录,i就是我要插入的对象,p是我要插入的地方
cin>>p>>f;
add(i,p,f);
}
cin>>m;
while(m--){
cin>>b;
a[b].resist=1;
}
for(int i=a[0].r;i;i=a[i].r){
if(a[i].resist==0) cout<<i<<' ';
}
return 0;
}
上周博客写完了,又得去赶这周的作业了,生活不就是苦中作乐吗?
下周见呜呜呜