目录
L1 - 6 剪切复制
L1 - 8 小偷踩点
L2 - 1 推宝塔
L2 - 2 含茶量
L2 - 3 到底爱不爱我
L2 - 4 寻宝图
L1 - 6 剪切复制
使用计算机进行文本编辑时常见的功能是剪切功能(快捷键:Ctrl + X)。请实现一个简单的具有剪切和粘贴功能的文本编辑工具。
工具需要完成一系列剪切后粘贴的操作,每次操作分为两步:
- 剪切:给定需操作的起始位置和结束位置,将当前字符串中起始位置到结束位置部分的字符串放入剪贴板中,并删除当前字符串对应位置的内容。例如,当前字符串为
abcdefg
,起始位置为 3,结束位置为 5,则剪贴操作后, 剪贴板内容为cde
,操作后字符串变为abfg
。字符串位置从 1 开始编号。 - 粘贴:给定插入位置的前后字符串,寻找到插入位置,将剪贴板内容插入到位置中,并清除剪贴板内容。例如,对于上面操作后的结果,给定插入位置前为
bf
,插入位置后为g
,则插入后变为abfcdeg
。如找不到应该插入的位置,则直接将插入位置设置为字符串最后,仍然完成插入操作。查找字符串时区分大小写。
每次操作后的字符串即为新的当前字符串。在若干次操作后,请给出最后的编辑结果。
输入格式:
输入第一行是一个长度小于等于 200 的字符串 S,表示原始字符串。字符串只包含所有可见 ASCII 字符,不包含回车与空格。
第二行是一个正整数 N (1≤N≤100),表示要进行的操作次数。
接下来的 N 行,每行是两个数字和两个长度不大于 5 的不包含空格的非空字符串,前两个数字表示需要剪切的位置,后两个字符串表示插入位置前和后的字符串,用一个空格隔开。如果有多个可插入的位置,选择最靠近当前操作字符串开头的一个。
剪切的位置保证总是合法的。
输出格式:
输出一行,表示操作后的字符串。s
AcrosstheGreatWall,wecanreacheverycornerintheworld
5
10 18 ery cor
32 40 , we
1 6 tW all
14 18 rnerr eache
1 1 e r
输出样例:
he,allcornetrrwecaneacheveryGreatWintheworldAcross
AC 代码
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
int n;
cin >> s >> n;
while (n--)
{
int start = 0, end = 0;
string s1, s2;
cin >> start >> end;
cin >> s1 >> s2;
start -= 1, end -= 1;
string tmp = s.substr(start, end - start + 1);
s.erase(start, end - start + 1);
s2 = s1 + s2;
if (s.find(s2) != -1) s.insert(s.find(s2) + s1.size(), tmp);
else s+= tmp;
}
cout << s;
return 0;
}
L1 - 8 小偷踩点
俗话说不怕贼偷,就怕贼惦记。
小偷在作案前有时会在居民家的门、墙上做一些标记,每一种记号代表一个含义,一般人看不懂,但同行一看便知道这个家庭的情况。不过派出所干警也不是吃素的,很快破译了这些记号的含义(如上图),并且在辖区内广为张贴,告知居民。
随后小偷们又改变了方法,将这些记号从 1 到 N 编号,然后将这些编号按照某种规则重新打乱再做标记,标记变成了一串数字。不过这种新的编号方法又被破译了!干警们发现这些数字的规律可以用一个二维矩阵来表示:矩阵有 10 列,顺序对应数字 0 到 9;矩阵一般不超过 10 行,每行对应一个 0 到 9 之间的数字,这些数字保证不重复。小偷的新标记由若干个两位数组成,每个数字的十位对应行、个位对应列,而对应位置上的数字就是原始标记的编号。
如上图 40 种标记从上到下、从左到右顺序编号后,按下图所示的规律打乱,则如果我们看到标记“71”,就是行标记为 7,列标记为 1 的单元格对应的数字 11,对应原始标记中第 11 个,即“很有钱”。那么标记“71 78 57”就表示原始标记的第 11、8、7 号,意思是“很有钱”、“没有防范”、“计划行动”。
本题就请你编写程序,自动破译小偷的新标记。
输入格式:
输入第一行给出 2 个正整数:N(≤100)为小偷的原始标记个数,M(≤10)为新标记对照矩阵的行数。
随后 N 行,第 i 行给出第 i 个标记的解释,由不超过 100 个英文字母和空格组成。
接下来一行给出 M 个数字,为 0 到 9 之间的数字,保证不重复,其中第 i 个数对应矩阵第 i 行。
接下来 M 行,每行给出 10 个数字,或者是 1 到 N 之间的一个编号,或者是 −1 表示没有对应的编号。
最后一行给出小偷留在墙上的数字标记,格式为:
k t[1] ... t[k]
其中 k
是数字个数(不超过 N),后面跟着 k
个数字。
输出格式:
对小偷留下的每个数字,在一行中输出其对应的意义,顺序与输入顺序相同。如果没有对应的意义,则在对应行中输出 ?
。
输入样例:
10 2
jia li you ren
kong fang zi
jia you e gou
dan shen
hen you qian
xiao xin lin ju
you bao jing qi
jin kuai dong shou
xia ci zai lai
bu bi jin ru
6 2
-1 6 5 1 -1 10 3 4 -1 9
2 4 7 -1 3 -1 5 -1 8 2
5 20 64 61 22 13
输出样例:
kong fang zi
?
xiao xin lin ju
you bao jing qi
?
AC 代码
#include <bits/stdc++.h>
using namespace std;
int r[11];
int nums[11][11];
int main()
{
int n, m;
int a;
cin >> n >> m;
vector<string> inform(n + 1);
getchar();
for (int i = 1; i <= n; i++)
{
getline(cin, inform[i]);
}
vector<int> hash(11);
for (int i = 1; i <= m; i++)
{
cin >> hash[i];
}
for (int i = 1; i <= m; i++)
for (int j = 0; j < 10; j++)
{
cin >> nums[hash[i]][j];
}
// 开始询问
int k = 0;
cin >> k;
while (k--)
{
int tmp = 0;
cin >> tmp;
int y = tmp % 10;
int x = tmp / 10;
if (nums[x][y] == -1 || nums[x][y] == 0) cout << "?" << endl;
else cout << inform[nums[x][y]] << endl;
}
return 0;
}
L2 - 1 推宝塔
堆宝塔游戏是让小朋友根据抓到的彩虹圈的直径大小,按照从大到小的顺序堆起宝塔。但彩虹圈不一定是按照直径的大小顺序抓到的。聪明宝宝采取的策略如下:
- 首先准备两根柱子,一根 A 柱串宝塔,一根 B 柱用于临时叠放。
- 把第 1 块彩虹圈作为第 1 座宝塔的基座,在 A 柱放好。
- 将抓到的下一块彩虹圈 C 跟当前 A 柱宝塔最上面的彩虹圈比一下,如果比最上面的小,就直接放上去;否则把 C 跟 B 柱最上面的彩虹圈比一下:
-
- 如果 B 柱是空的、或者 C 大,就在 B 柱上放好;
-
- 否则把 A 柱上串好的宝塔取下来作为一件成品;然后把 B 柱上所有比 C 大的彩虹圈逐一取下放到 A 柱上,最后把 C 也放到 A 柱上。
重复此步骤,直到所有的彩虹圈都被抓完。最后 A 柱上剩下的宝塔作为一件成品,B 柱上剩下的彩虹圈被逐一取下,堆成另一座宝塔。问:宝宝一共堆出了几个宝塔?最高的宝塔有多少层?
输入格式:
输入第一行给出一个正整数 N(≤103),为彩虹圈的个数。第二行按照宝宝抓取的顺序给出 N 个不超过 100 的正整数,对应每个彩虹圈的直径。
输出格式:
在一行中输出宝宝堆出的宝塔个数,和最高的宝塔的层数。数字间以 1 个空格分隔,行首尾不得有多余空格。
输入样例:
11
10 8 9 5 12 11 4 3 1 9 15
输出样例:
4 5
AC 代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 1010;
int nums[N];
int main()
{
int n;
cin >> n;
vector<int> va;
vector<int> vb;
int cnt = 0;
int res = 0;
for(int i = 0; i < n; i++)
{
cin >> nums[i];
if(va.size() == 0 || nums[i] < va.back())
va.push_back(nums[i]);
else if(vb.size() == 0 || nums[i] > vb.back())
vb.push_back(nums[i]);
else
{
res = max(res, (int)va.size());
va.clear();
cnt ++;
while(vb.back() > nums[i])
{
int tm = vb.back();
va.push_back(tm);
vb.pop_back();
}
va.push_back(nums[i]);
}
}
if(va.size() > 0) cnt ++;
res = max(res, (int)va.size());
cout << cnt << " " << res << endl;
return 0;
}
L2 - 2 含茶量
天梯赛模拟赛 L2 —— 含茶量
L2 - 3 到底爱不爱我
古代少女有了心上人时,会悄悄折一条树枝,揪那枝上的叶子,揪一片叶子念一句“爱我”,再揪一片念一句“不爱我”…… 这样揪落最后一片叶子的时候,看看是停在“爱”还是“不爱”。
但聪明的慧娘一眼洞穿,只要数一下叶子有多少片,根据这个数字的奇偶性判断是以“爱”开始还是以“不爱”开始,就总是可以最后落在“爱”上。这个游戏顿时就变得无趣了 —— 真的是文科生制造浪漫,理科生杀死浪漫。
于是有着工科生大脑的慧娘打算另外制作一个更有趣的浪漫游戏。她用不同植物的枝条做成了三种“情枝”:
- “专情枝”:是一根有两个分岔的树枝,只有当两个分岔上连接的枝条传过来的情话都是“爱”的时候,这根枝条的根部才传出“爱”;否则树枝根部传出的是“不爱”。
- “博爱枝”:也是一根有两个分岔的树枝,只有当两个分岔上连接的枝条传过来的情话都是“不爱”的时候,这根枝条的根部才传出“不爱”;否则树枝根部传出的都是“爱”。
- “情变枝”:是没有分岔的一根直枝,如果一端接到“爱”,另一端必须传出“不爱”;反之如果一端接到“不爱”,另一端则会传出“爱”。
慧娘将这些树枝摆放在院子里,布了一个“情阵”,先选一根特殊的枝条作为初试一枝,从这枝条的根部开始,扩散开去,令它们根枝相连。然后她在末梢的枝杈旁随意写下“爱”或“不爱”。现在请你写个程序帮她算出来,在初始一枝的根部,她能得到“爱”还是“不爱”?
输入格式:
输入在第一行中给出正整数 N(≤30),是慧娘制作的情枝数量。这里假设她将所有的情枝从 1 到 N 做好了编号。随后 N 行,第 i 行给出第 i 枝的描述,格式为
类型 左分枝连接的编号 右分枝连接的编号
其中 类型
为 1 代表专情、2 代表博爱、3 代表情变。当然如果是情变枝,则后面跟的是其唯一末端连接的情枝编号,并没有两个分枝的信息。如果一个分枝是末梢,并没有连接其它枝条,则对应编号为 0。
接下来一行中给出正整数 K(≤30),是慧娘询问的次数。以下 K 行,每行给出一个由 0
和 1
组成的字符串,其中 0
表示“不爱”,1
表示“爱”—— 这是慧娘从左到右在每个枝杈末梢处写下的。(注意:“从左到右”的意思是,我们从初试一枝出发去遍历所有枝条的末梢时,总是遵循先遍历左边情阵、再遍历右边情阵的顺序)
输出格式:
对慧娘的每个询问,如果她在初始一枝的根部能得到“爱”,就输出 Ai
;否则输出 BuAi
。
输入样例:
6
2 6 4
1 0 0
3 1
2 0 0
3 0
1 5 2
5
11111
00000
11100
10011
01100
输出样例:
BuAi
Ai
Ai
BuAi
BuAi
样例说明:
样例对应的情阵以及慧娘第 3 问的情势如图所示,其中完整的心对应 1
,裂开的心对应 0
。
AC 代码
#include<bits/stdc++.h>
using namespace std;
const int N = 32;
int ty[31];
int con[31][3]; // 第 i 个分支左右连接的分支编号
int hapa[31]; // 记录 i 个分支是否有父节点 // 为了找父节点, 根节点没有父节点
bool dfs(int x)
{
if(x == 0) // 到了叶子节点,刚好输入数据!
{
char ch;
cin >> ch;
return ch - '0';
}
if(ty[x] == 1)
return dfs(con[x][0]) & dfs(con[x][1]);
else if(ty[x] == 2)
return dfs(con[x][0]) | dfs(con[x][1]);
else return dfs(con[x][0]) ^ 1;
}
int main()
{
int n = 0;
cin >> n; // 情枝数量
for(int i = 1; i <= n; i++)
{
cin >> ty[i];
if(ty[i] == 1 || ty[i] == 2)
{
cin >> con[i][0];
cin >> con[i][1];
hapa[con[i][0]] ++; // 记录有父节点的情枝
hapa[con[i][1]] ++;
}
else
{
cin >> con[i][0];
hapa[con[i][0]] ++; // 记录有父节点的情枝
}
}
// 找到根节点
int i = 0;
for(i = 1; i <= n; i++)
{
if(hapa[i] == 0) break;
}
// 根节点为 i
int k = 0; // 询问次数
cin >> k;
while(k--)
{
if(dfs(i)) cout << "Ai" << endl;
else cout << "BuAi" << endl;
}
return 0;
}
L2 - 4 寻宝图
给定一幅地图,其中有水域,有陆地。被水域完全环绕的陆地是岛屿。有些岛屿上埋藏有宝藏,这些有宝藏的点也被标记出来了。本题就请你统计一下,给定的地图上一共有多少岛屿,其中有多少是有宝藏的岛屿。
输入格式:
输入第一行给出 2 个正整数 N 和 M(1<N×M≤105),是地图的尺寸,表示地图由 N 行 M 列格子构成。随后 N 行,每行给出 M 位个位数,其中 0
表示水域,1
表示陆地,2
-9
表示宝藏。
注意:两个格子共享一条边时,才是“相邻”的。宝藏都埋在陆地上。默认地图外围全是水域。
输出格式:
在一行中输出 2 个整数,分别是岛屿的总数量和有宝藏的岛屿的数量。
输入样例:
10 11
01000000151
11000000111
00110000811
00110100010
00000000000
00000111000
00114111000
00110010000
00019000010
00120000001
输出样例:
7 2
过 96% 测试代码(24分)
#include <bits/stdc++.h>
using namespace std;
const int N = 10010;
int nums[N][N];
bool vis[N][N];
int dx[4] = {0, 0, 1, -1};
int dy[4] = {1, -1, 0, 0};
int m,n;
int cnt1, cnt2;
int flag;
void dfs(int i, int j)
{
if(nums[i][j] > 1) flag = 1; // 防止进递归的第一个数就是大于 1 的数
for(int k = 0; k < 4; k++)
{
int x = i + dx[k];
int y = j + dy[k];
if(x >= 1 && x <= m && y >= 1 && y <= n &&
!vis[x][y] && nums[x][y] > 0)
{
if(nums[x][y] > 1) flag = 1;
vis[x][y] = true;
dfs(x, y);
}
}
}
int main()
{
cin >> m >> n;
string s;
for(int i = 1; i <= m; i++)
{
cin >> s;
for(int j = 1; j <= n; j++)
{
nums[i][j] = s[j - 1] - '0';
}
}
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
if(nums[i][j] > 0 && !vis[i][j])
{
cnt1++;
vis[i][j] = true;
dfs(i, j);
if(flag == 1) cnt2 ++;
flag = 0;
}
cout << cnt1 << " " << cnt2 << endl;
return 0;
}