题解Week7

题解Week7

四月 14, 2022

7-1

你刚从滑铁卢搬到了一个大城市,这里的人们讲一种难以理解的外语方言。幸运的是,你有一本字典来帮助你理解它们。

输入格式:

输入第一行是正整数N和M,后面是N行字典条目(最多10000条),然后是M行要翻译的外语单词(最多10000个)。每一个字典条目都包含一个英语单词,后面跟着一个空格和一个外语单词。 输入中的每个单词都由最多10个小写字母组成。

输出格式:

输出翻译后的英文单词,每行一个单词。非词典中的外来词汇输出“eh”。

我是fw,我不会map。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>
#include <cstring>
using namespace std;
struct dictory{
string ori;
string hon;
};
int main(){
int n,m;
cin >> n >> m;
dictory dic[n];
for(int i=0;i<n;i++){
cin >> dic[i].ori >> dic[i].hon;
}
string honlan;
for(int abc=0;abc<m;abc++){
bool found=false;
cin >> honlan;
for(int i=0;i<n;i++){
if(dic[i].hon==honlan) {cout << dic[i].ori << endl;found=true;break;}
}
if(!found) cout << "eh" << endl;
}
return 0;
}

7-2

传说二战时X国收到了上帝的一串密码,只有解开密码,才能阻止战争的继续进行,世界才会恢复和平。解开密码的第一道工序就是解压缩密码,上帝对于连续的若干个相同的子串”X”会压缩为”[DX]”的形式(D是一个整数且1<=D<=99),比如说字符串”CBCBCBCB”就压缩为”[4CB]”或者”[2[2CB]]”,类似于后面这种压缩之后再压缩的称为二重压缩。如果是”[2[2[2CB]]]”则是三重的。现在我们给你上帝发送的密码,请你对其进行解压缩。

输入格式:

一个字符串

输出格式:

一个字符串

我这道题pta过了但是luogu没过然后我就发现有点小bug,最后改了

这道题我第一次尝试找括号,左边第一个[和右边第一个]配对,然后递归找[]里面的。后来发现这样不行因为有些样例比如说是3[3AC]BB[2DE],这样用左右配对会出bug.

于是就需要遍历,第二次尝试,从左往右逐渐遍历,遍历到第一个就找[]里的,但这样应对不了二重的解压缩,于是就需要找相对应的]来匹配。

于是就需要一个计数器,在遍历’]’的时候要寻找下[的次数,否则会无法应对二重。

另外,每一次返回[]内的数,要检查一下[]里面是否是已经解压的。

比如2[2[2AC]],不进行检查的话十分容易出现2ACAC2ACAC这个结果。

具体思路就是找到了[],开拆,拆了[前的[]中的和]后的,然后就把[]中间的给unpack了,再把三段拼接起来,注意遍历的下标的位置需要发生改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
#include <iostream>
using namespace std;
string unpack(string str){
bool isclean=true;
int i=0,j;
for(i=0;i<str.size();i++){
if(str[i]=='['){
isclean=false;
break;
}
}
if(isclean){
int doublestatus=1;
string newstr="",cutstr="";
if(str[0]>='0'&&str[0]<='9'){
if(str[1]>='0'&&str[1]<='9'){
doublestatus=((int)(str[0]-'0'))*10+(int)(str[1]-'0');
for(int a=2;a<str.size();a++) cutstr+=str[a];
for(int a=1;a<=doublestatus;a++) newstr+=cutstr;
return newstr;
}else{
doublestatus=(int)(str[0]-'0');
for(int a=1;a<str.size();a++) cutstr+=str[a];
for(int a=1;a<=doublestatus;a++) newstr+=cutstr;
return newstr;
}
}else return str;
}else{
string newstr="",shouldunpackstr="";
for(int p=0;p<str.size();p++){
int intoleft=0;
shouldunpackstr="";
if(str[p]!='[') newstr+=str[p];
else if(str[p]=='['){
intoleft=1;
for(j=p+1;j<str.size();j++){
if(str[j]=='[') intoleft++;
if(str[j]==']') intoleft--;
if(str[j]==']'&&intoleft==0) break;
shouldunpackstr+=str[j];
}
newstr+=unpack(shouldunpackstr);
p=j;
}
}
return unpack(newstr);
}
}
int main(){
string strori;
cin >> strori;
cout << unpack(strori) << endl;
return 0;
}

luogu能AC


7-3

输入两个字符串,从第一个字符串中删除第二个字符串中的所有字符。例如,输入“They are students.”和“aeiou”,则删除之后的第一个字符串变成“Thy r stdnts”。

输入格式:

输入包含多组测试,每个测试输入包含两个字符串。

输出格式:

输出删除后的字符串。

谢谢你,多组数据,让我白debug了好久

如果反复查找时间复杂度为O(n^2)会有点久。

可以做一个hash表,第二串数据输入进去时,因为一个字符对应一个ASCLL码,所以可以标记其为1。

再遍历第一串字符串,发现hash为1的直接跳。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <cstring>
using namespace std;
int hashing[257];
int main(){
string strori,strdel;
while(getline(cin,strori)){
getline(cin,strdel);
for(int i=0;i<257;i++) hashing[i]=0;
for(int i=0;i<strdel.size();i++){
hashing[(int)strdel[i]]=1;
}
for(int i=0;i<strori.size();i++){
if(hashing[(int)strori[i]]==0) cout << strori[i];
}
cout << endl;
}
return 0;
}

7-4

对于给定一个数字序列 (a 1,a2,…,a n) ,如果满足a
1<a 2<…<a 3 ,则称该序列是有序的。若在序列(a 1 ,a 2 ,…,a n) 中删除若干元素得到的子序列是有序的,则称该子序列为一个有序子序列。有序子序列中长度最大的即为最长有序子序列。
例如,(1,3,5)、(3,5,8)、(1,3,5,9)等都是序列 (1,7,3,5,9,4,8) 的有序子序列;而(1,3,5,9)、(1,3,5,8)、(1,3,4,8)都是序列 (1,7,3,5,9,4,8)的一个最长有序子序列,长度为4。
请编写程序,求出给定数字序列中的最长有序子序列的长度。

输入格式:

首先输入一个正整数T,表示测试数据的组数,然后是T组测试数据。每组测试数据第一行输入一个整数 n(1≤n≤1000),第二行输入n个整数,数据范围都在[0,10000],数据之间以一个空格分隔。

输出格式:

对于每组测试,输出n个整数所构成序列的最长有序子序列的长度。每两组测试的输出之间留一个空行。

经典DP题,时间复杂度为O(n^2)。

设一个数组为dp,代表了这个数字前的最大递增子序列。

dp初始值固然为1(我一开始傻了全设成了0),从0开始遍历,往前找一个比自己小的数字。

状态转移方程为dp[i]=max(dp[i],dp[j]+1)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <cstring>
using namespace std;
int dp[1005],a[1005];
int main(){
int T;
cin >> T;
for(int abc=1;abc<=T;abc++){
int n;
int _max=1;
cin >> n;
for(int i=0;i<n;i++) {cin >> a[i];dp[i]=1;}
for(int i=1;i<n;i++){
for(int j=0;j<i;j++){
if(a[i]>a[j]) {dp[i]=max(dp[i],dp[j]+1);}
}
}
for(int i=0;i<n;i++){
if(dp[i]>_max) _max=dp[i];
}
cout << _max << endl;
if(abc!=T) cout << endl;
}
}

7-5

谢谢你,多组数据,让我白debug了好久

给定n种物品(每种仅一个)和一个容量为c的背包,要求选择物品装入背包,使得装入背包中物品的总价值最大。

输入格式:

测试数据有多组,处理到文件尾。每组测试数据输入3行,第1行为两个整数n(1≤n≤400)和c (1≤c≤1500),分别表示物品数量与背包容量,第二行为n个物品的重量w
i(1≤i≤n),第三行为这n个物品的价值v i (1≤i≤n)。物品重量、价值都为整数。

输出格式:

对于每组测试,在一行上输出一个整数,表示装入背包的最大总价值(结果保证在int范围内)。

因为无意义的反复debug(没看到多组数据ASWLAAAAA),所以写了两种。

1、费时间,省空间:

这种思路是把以背包容量为主体,首先就是判断当前的背包容量能否装得下这个物品,如果装不下不管它。如果能装,就判断装和不装那种情况更好,不装就是当前背包容得下最大物品的价值,装就是当前背包剩余-体积这个背包的最大价值加上现在的价值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
int things,maxkilo,bagrommax[1505];
int main()
{
while(cin >> things >> maxkilo){
for(int i=0;i<=maxkilo+3;i++) bagrommax[i]=0;
int value[things+1],kilo[things+1];
for(int i=1;i<=things;i++) cin >> kilo[i];
for(int i=1;i<=things;i++) cin >> value[i];
kilo[0]=value[0]=0;
for(int i=1;i<=things;i++){
int j;
for(j=maxkilo;j>0;j--){
if(kilo[i]<=j) bagrommax[j]=max(bagrommax[j],bagrommax[j-kilo[i]]+value[i]);
}
}
cout << bagrommax[maxkilo] << endl;
}
return 0;
}

2、省时间,费空间:

这种思路是常见的开二维数组的思想,以物品为主体。一个下标表示剩余容量,一个下标表示物品。每个dp代表着当前背包容量装前几个物品的最大价值。可见0容量和0物品的价值全部为0。判断时,如果背包的容量比当前物品小了,那这个格子的值为前面物品放入这个背包的最大价值,如果背包能装下这个物品,就判断装不装更有价值,不装同上,也是为前面物品放入这个背包的最大价值,如果装,就是要前面物品放入体积-当前物品这个容量的背包加上当前最大值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
using namespace std;
int dp[1505][405];
int value[405],kilo[405];
int main(){
int nimotsu;
int maxkilo;
while(cin>>nimotsu>>maxkilo){
for(int i=0;i<405;i++){value[i]=0;kilo[i]=0;}
value[0]=0;
kilo[0]=0;
for(int i=1;i<=nimotsu;i++) cin >> kilo[i];
for(int i=1;i<=nimotsu;i++) cin >> value[i];
for(int i=0;i<=maxkilo;i++) dp[i][0]=0;
for(int i=0;i<=nimotsu;i++) dp[0][i]=0;
for(int i=1;i<=maxkilo;i++) {
for(int j=1;j<=nimotsu;j++) {
if(kilo[j]>i) dp[i][j]=dp[i][j-1];
else{
if(dp[i][j-1]>dp[i-kilo[j]][j-1]+value[j]) dp[i][j]=dp[i][j-1];
else dp[i][j]=dp[i-kilo[j]][j-1]+value[j];
}
}
}
cout << dp[maxkilo][nimotsu] << endl;
}
return 0;
}
审题不谨慎,debug两行泪。