L1-110 这不是字符串题 - java
L1-110 这不是字符串题
语言 | 时间限制 | 内存限制 | 代码长度限制 | 栈限制 |
---|---|---|---|---|
Java (javac) | 1100 ms | 512 MB | 16KB | 8192 KB |
其他编译器 | 400 ms | 64 MB | 16KB | 8192 KB |
题目描述:
因为每年天梯赛字符串题的解答率都不尽如人意,因此出题组从几年前开始决定:每年的天梯赛的 15 15 15 分一定会有一道字符串题,另外一道则一定不是字符串题。
小特现在有 N N N 个正整数 A i A_{i} Ai ,不知道为什么,小特打算“动”一下这些数字, 具体而言,她希望做 M 次操作,每次是以下三种操作之一:
- 在当前正整数序列里查找给定的连续正整数序列是否存在,如存在,则将其替换成另外一个正整数序列;
- 对于当前整个正整数序列,如果相邻之间的数字和为偶数,则在它们中间插入它们的平均数;
- 翻转当前正整数序列指定下标之间的一段数字。这里的翻转指的是对于一段数字序列 A i , A i + 1 , … , A j − 1 , A j A_i, A_{i + 1}, \dots, A_{j - 1}, A_{j} Ai,Ai+1,…,Aj−1,Aj ,将其变为 A j , A j − 1 , … , A i + 1 , A i A_{j}, A_{j - 1}, \dots, A_{i + 1}, A_i Aj,Aj−1,…,Ai+1,Ai。
请你输出按输入顺序依次完成若干次操作后的结果。
输入格式:
输入第一行是两个正整数 N , M ( 1 ≤ N , M ≤ 10 3 ) N,M (1 \le N, M \le 10^3) N,M(1≤N,M≤103),分别表示正整数个数以及操作次数。
接下来的一行有 N N N 个用一个空格隔开的正整数 A i ( 1 ≤ A i ≤ 26 ) A_i(1 \le A_i \le 26) Ai(1≤Ai≤26),表示需要进行操作的原始数字序列。
紧接着有 M M M 部分,每一部分表示一次操作,你需要按照输入顺序依次执行这些操作。记 L L L 为当前操作序列长度(注意原始序列在经过数次操作后,其长度可能不再是 N N N)。每部分的格式与约定如下:
- 第一行是一个 1 1 1 到 3 3 3 的正整数,表示操作类型,对应着题面中描述的操作( 1 1 1 对应查找-替换操作, 2 2 2 对应插入平均数操作, 3 3 3 对应翻转操作);
- 对于第 1 1 1 种操作:
- 第二行首先有一个正整数 L 1 ( 1 ≤ L 1 ≤ L ) L_1 (1 \le L_1 \le L) L1(1≤L1≤L),表示需要查找的正整数序列的长度,接下来有 L 1 L_1 L1个正整数(范围与 A i A_i Ai 一致),表示要查找的序列里的数字,数字之间用一个空格隔开。查找时序列是连续的,不能拆分。
- 第三行跟第二行格式一致,给出需要替换的序列长度 L 2 L_2 L2 和对应的正整数序列。如果原序列中有多个可替换的正整数序列,只替换第一个数开始序号最小的一段,且一次操作只替换一次。注意 L 2 L_2 L2 范围可能远超出 L L L。
- 如果没有符合要求的可替换序列,则直接不进行任何操作。
- 对于第 2 种操作:
- 没有后续输入,直接按照题面要求对整个序列进行操作。
- 对于第 3 种操作:
- 第二行是两个正整数 l , r ( 1 ≤ l ≤ r ≤ L ) l,r (1 \le l \le r \le L) l,r(1≤l≤r≤L),表示需要翻转的连续一段的左端点和右端点下标(闭区间)。
每次操作结束后的序列为下一次操作的起始序列。
保证操作过程中所有数字序列长度不超过 100 N 100N 100N。题目中的所有下标均从 1 1 1 开始。
输出格式:
输出进行完全部操作后的最终正整数数列,数之间用一个空格隔开,注意最后不要输出多余空格。
输入样例:
39 5
14 9 2 21 8 21 9 10 21 5 4 5 26 8 5 26 8 5 14 4 5 2 21 19 8 9 26 9 6 21 3 8 21 1 14 20 9 2 1
1
3 26 8 5
2 14 1
3
37 38
1
11 26 9 6 21 3 8 21 1 14 20 9
14 1 2 3 4 5 6 7 8 9 10 11 12 13 14
2
3
2 40
输出样例:
14 9 8 7 6 5 4 3 2 1 5 9 8 19 20 21 2 5 4 9 14 5 8 17 26 1 14 5 4 5 13 21 10 9 15 21 8 21 2 9 10 11 12 13 14 1 2
样例解释:
为方便大家理解题意和调试程序,以下为样例每一步的中间操作序列结果:
第 1 1 1 次操作结束后:
14 9 2 21 8 21 9 10 21 5 4 5 14 1 26 8 5 14 4 5 2 21 19 8 9 26 9 6 21 3 8 21 1 14 20 9 2 1
注意这里只会替换第一次的序列。
第 2 次操作结束后:
14 9 2 21 8 21 9 10 21 5 4 5 14 1 26 8 5 14 4 5 2 21 19 8 9 26 9 6 21 3 8 21 1 14 20 9 1 2
第 3 次操作结束后:
14 9 2 21 8 21 9 10 21 5 4 5 14 1 26 8 5 14 4 5 2 21 19 8 9 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2
第 4 次操作结束后:
14 9 2 21 8 21 15 9 10 21 13 5 4 5 14 1 26 17 8 5 14 9 4 5 2 21 20 19 8 9 5 1 2 3 4 5 6 7 8 9 10 11 12 13 14 1 2
按照要求执行指定操作
- 操作为1
- 将序列a替换为序列b
- 操作为2
- 在相邻两个数字之和为偶数的中间插入这两个数的平均值
- 操作为3
- 将L到R之间的所有数翻转
emmmmmmm
这道题目有两种方法实现
- 第一种: 暴力模拟
- 操作为1时
- 先将两个序列先进行输入
- 再判断原序列当中是否存在指定序列a
- 可以暴力判断
// 存在连续的整数序列下的起始位置 int start = -1; for (int i = 1; i <= n; i++) {// 判断是否存在连续的整数序列for (int j = 1; j <= l1; j++){// 从当前位置开始到达的第j个位置与指定的连续序列不同,则表示当前从第i个位置开始的整数序列不存在if (shu[i + j - 1] != a[j]) break;// 如果能完全找到连续的整数序列,则替换起始位置if (j == l1) start = i;}// 存在连续的整数序列if (start != -1) break; }
- 也可以利用小技巧
// 存在连续的整数序列下的结束位置 int end = -1; // 记录序列a在原序列中连续出现的次数 int j = 1; for (int i = 1; i <= n; i++) {// 如果当前的数与第j个数相同if (shu[i] == a[j]) j++;// 如果当前的数与第j个数不相同,则将其与序列a中的第1个数进行判断else if (shu[i] == a[1]) j = 2;// 如果都不相同,则重置else j = 1;// 如果连续出现的次数超过l1个,则表示序列a在原序列中存在if (j > l1){end = i;break;} }
- 可以暴力判断
- 如果存在
- 将数组中的序列a替换为序列b
- 操作为2时
- 依次枚举相邻两个元素
- 判断这两个元素之和是否为偶数
- 如果两个元素之和是偶数,则将这两个元素的平均值插入其中
- 操作为3时
- 翻转l到r之间的所有数
- 操作为1时
- 第二种: 利用类库“SB”实现
- 可以发现给定的正整数的范围都是 1 ∼ 26 1 \sim 26 1∼26, 可以发现其满足字母 a ∼ z a \sim z a∼z的范围。由于给定的操作有替换、翻转的功能,正好可以利用字符串快速实现。
- 操作为1时
- 利用
indexOf
判断序列a
在原序列
中存在的位置 - 如果存在, 则利用拼接的方法将
序列b
替换原序列中的序列a
- 利用
- 操作为2时
- 依次枚举相邻两个元素
- 判断这两个元素之和是否为偶数
- 如果两个元素之和是偶数,则将这两个元素的平均值插入其中
- 操作为3时
- 利用
reverse()
函数将StringBuilder
的字符串进行翻转 - 在利用拼接的方法翻转指定 l ∼ r l \sim r l∼r区间即可
- 利用
- 操作为1时
暴力模拟
import java.io.*;public class Main
{static int N = (int) 2e5;static int shu[] = new int[N + 10];static int res[] = new int[N + 10];static int a[] = new int[N + 10];static int b[] = new int[N + 10];static int n;static void op1() throws IOException{int l1 = ini();for (int i = 1; i <= l1; i++) a[i] = ini();int l2 = ini();for (int i = 1; i <= l2; i++) b[i] = ini();// 存在连续的整数序列下的起始位置int start = -1;for (int i = 1; i <= n; i++){// 判断是否存在连续的整数序列for (int j = 1; j <= l1; j++){// 从当前位置开始到达的第j个位置与指定的连续序列不同,则表示当前从第i个位置开始的整数序列不存在if (shu[i + j - 1] != a[j]) break;// 如果能完全找到连续的整数序列,则替换起始位置if (j == l1) start = i;}// 存在连续的整数序列if (start != -1) break;}// 如果不存在连续的整数序列if (start == -1) return;// 执行插入操作(依次存入 1~start, 替换后的内容, start+l1~n)int pos = 0;for (int i = 1; i < start; i++) res[++pos] = shu[i];for (int i = 1; i <= l2; i++) res[++pos] = b[i];for (int i = start + l1; i <= n; i++) res[++pos] = shu[i];// 更换数组n = pos;for (int i = 1; i <= n; i++) shu[i] = res[i];}static void op2() throws IOException{int pos = 1;for (int i = 1; i < n; i++){// 将当前位置的数填入res中res[pos++] = shu[i];// 如果满足条件,则在中间位置插入平均值if ((shu[i] + shu[i + 1]) % 2 == 0) res[pos++] = (shu[i] + shu[i + 1]) / 2;}// 填入最后的一个值res[pos] = shu[n];// 更换数组n = pos;for (int i = 1; i <= n; i++) shu[i] = res[i];}static void op3() throws IOException{int l = ini();int r = ini();// 翻转区间内的数组for (int i = 1; i < l; i++) res[i] = shu[i];for (int i = r, j = l; i >= l; i--, j++) res[j] = shu[i];for (int i = r + 1; i <= n; i++) res[i] = shu[i];// 更换数组for (int i = 1; i <= n; i++) shu[i] = res[i];}static void print(){for (int i = 1; i <= n; i++){if (i != 1) out.print(" ");out.print(shu[i]);}out.println();}public static void main(String[] args) throws IOException{n = ini();int m = ini();for (int i = 1; i <= n; i++) shu[i] = ini();while (m-- > 0){int op = ini();if (op == 1) op1();else if (op == 2) op2();else if (op == 3) op3();}print();out.flush();out.close();}static StreamTokenizer sc = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));static PrintWriter out = new PrintWriter(System.out);static int ini() throws IOException{sc.nextToken();return (int) sc.nval;}}
类库“SB”
import java.io.*;public class Main
{static StringBuilder s;// 将输入的数字序列转换为字符串static StringBuilder getString(int n) throws IOException{StringBuilder ans = new StringBuilder();for (int i = 1; i <= n; i++){int x = ini();ans.append((char) ('a' + x - 1));}return ans;}static void op1() throws IOException{int l1 = ini();StringBuilder a = getString(l1);int l2 = ini();StringBuilder b = getString(l2);// 获取序列a在序列s中的位置int start = s.indexOf(a.toString());// 如果存在,则将序列a替换序列bif (start != -1) s = new StringBuilder(s.substring(0, start) + b + s.substring(start + l1));}static void op2() throws IOException{// 将s转换为char数组char res[] = s.toString().toCharArray();// 清空ss = new StringBuilder();for (int i = 0; i < res.length - 1; i++){// 将当前位置的字符填入s中s.append(res[i]);int ans = (res[i] - 'a' + 1) + (res[i + 1] - 'a' + 1);// 如果满足条件,则在中间位置插入平均值if (ans % 2 == 0) s.append((char) (ans / 2 + 'a' - 1));}// 填入最后的一个值s.append(res[res.length - 1]);}static void op3() throws IOException{int l = ini() - 1;int r = ini() - 1;// // 翻转区间内的数组s = new StringBuilder( s.substring(0, l) + new StringBuilder(s.substring(l, r + 1)).reverse() + s.substring(r + 1) );}static void print(){char res[] = s.toString().toCharArray();for (int i = 0; i < res.length; i++){if (i != 0) out.print(" ");out.print(res[i] - 'a' + 1);}out.println();}public static void main(String[] args) throws IOException{int n = ini();int m = ini();s = getString(n);while (m-- > 0){int op = ini();if (op == 1) op1();else if (op == 2) op2();else if (op == 3) op3();}print();out.flush();out.close();}static StreamTokenizer sc = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));static PrintWriter out = new PrintWriter(System.out);static int ini() throws IOException{sc.nextToken();return (int) sc.nval;}}
indexOf
StringBuilder
如果有说错的 或者 不懂的 尽管提 嘻嘻
一起进步!!!
闪现