202409-1 平衡序列
题目描述
小杨有一个包含 n 个正整数的序列 a。他认为一个序列是平衡的当且仅当存在一个正整数 i(1 \leq i < n)使得序列第 1 到第 i 个数字的总和等于第 i + 1 到第 n 个数字的总和。
小杨想请你判断序列 a 是否是平衡的。
输入格式
本题单个测试点内包含多组测试数据。第一行是一个正整数 t,表示测试用例组数。
接下来是 t 组测试用例。对每组测试用例,一共两行。
第一行包含一个正整数 n,表示序列长度。
第二行包含 n 个正整数,代表序列 a。
输出格式
对每组测试用例输出一行一个字符串。如果 a 是平衡的,输出 \texttt{Yes},否则输出 \texttt{No}。
样例输入 1
3
3
1 2 3
4
2 3 1 4
5
1 2 3 4 5
样例输出 1
Yes
Yes
No
提示
【样例 1 解释】
- 对第一组测试用例,令 i = 2,有 i + 2 = 3,因此序列是平衡的。
- 对第二组测试用例,令 i = 2,有 2 + 3 = 1 + 4,因此序列是平衡的。
- 对第三组测试用例,不存在满足要求的 i。
【数据规模与约定】
对全部的测试数据,保证 1 \leq t \leq 100,1 \leq n, a_i \leq 10000。
代码解析
达到平衡序列的条件是把一个数组分成两半,左半部分的和和右半部分的和相等,这道题使用枚举法,枚举的
i
表示我们从哪里将数组分开,分别求a[1]
~a[i]
与a[i+1]
~a[n]
的和,判断是否相等即可,使用flag
进行标记。
#include<bits/stdc++.h>
using namespace std;
int main() {
int t, a[10005];
cin >> t;
while(t--) {
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
bool flag = false;
for (int i = 1; i < n; i++) {
int sum1 = 0, sum2 = 0;
// 计算左半部分的和
for (int j = 1; j <= i; j++)
sum1 += a[j];
// 计算右半部分的和
for (int j = i+1; j <= n; j++)
sum2 += a[j];
if (sum1 == sum2) {
flag = true;
break;
}
}
if (flag) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
202409-2 回文拼接
题目描述
一个字符串是回文串,当且仅当该字符串从前往后读和从后往前读是一样的,例如,\texttt{aabaa} 和 \texttt{ccddcc} 都是回文串,但 \texttt{abcd} 不是。
小杨有 n 个仅包含小写字母的字符串,他想请你编写程序判断每个字符串是否由两个长度至少为 2 的回文串前后拼接而成。
输入格式
第一行包含一个正整数 n,代表字符串数量。
接下来 n 行,每行一个仅包含小写字母的字符串。
输出格式
对于每个字符串输出一行,如果该字符串由两个长度至少为 2 的回文串前后拼接而成则输出 Yes,否则输出 No。
样例输入 1
4
abcd
aabbb
aaac
abcdd
样例输出 1
No
Yes
No
No
提示
【样例 1 解释】
对于第 1,3,4 个字符串,都不是由两个长度至少为 2 的回文串前后拼接而成。
第 2 个字符串由回文串 \texttt{aa} 和 \texttt{bbb} 前后拼接而成,并且两个回文串长度都至少为 2。
【数据规模与约定】
对全部的测试数据,保证 1 \leq n \leq 10,且每个字符串的长度均不超过 100。
代码解析
和上道题一样的思路,我们枚举切开的位置,判断切开之后左边部分和右半部分是不是均为回文字符串,多了一个条件,如果切开之后字符串长度小于 2 则不满足。
从
i
切开,前半部分就是s.substr(0, i)
后半部分是s.substr(i)
。
#include<bits/stdc++.h>
using namespace std;
bool hui(string s) {
// 两个回文串长度都至少为 2
if (s.size() < 2) return false;
string s1;
for (int i = 0; i < s.size(); i++)
s1 = s[i] + s1;
return s == s1;
}
int main() {
int n;
cin >> n;
while (n--) {
string s;
cin >> s;
bool flag = false;
for (int i = 1; i < s.size(); i++) {
if (hui(s.substr(0, i)) && hui(s.substr(i))) {
flag = true;
break;
}
}
if (flag) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
202406-1 移位
题目描述
小杨学习了加密技术移位,所有大写字母都向后按照⼀个固定数目进行偏移。偏移过程会将字母表视作首尾相接的环,例如,当偏移量是 3 的时候,大写字母 A 会替换成 D,大写字母 Z 会替换成 C,总体来看,大写字母表 ABCDEFGHIJKLMNOPQRSTUVWXYZ 会被替换成 DEFGHIJKLMNOPQRSTUVWXYZABC。
注:当偏移量是 26 的倍数时,每个大写字母经过偏移后会恰好回到原来的位置,即大写字母表 ABCDEFGHIJKLMNOPQRSTUVWXYZ 经过偏移后会保持不变。
输入格式
第一行包含一个正整数 n。
输出格式
输出在偏移量为 n 的情况下,大写字母表 ABCDEFGHIJKLMNOPQRSTUVWXYZ 移位替换后的结果。
样例输入 1
3
样例输出 1
DEFGHIJKLMNOPQRSTUVWXYZABC
提示
【样例解释】
当偏移量是 3 的时候,大写字母 A 会替换成 D,大写字母 Z 会替换成 C,总体来看,大写字母表 ABCDEFGHIJKLMNOPQRSTUVWXYZ 会被替换成 DEFGHIJKLMNOPQRSTUVWXYZABC。
【数据范围】
对于全部数据,保证有 1\leq n\leq 100。
代码解析
0 ~ 25 这组数字加 'A' 就能构建一个大写字母表,所以我们先将 0 ~ 25 的数字进行偏移处理,先 +n,再取余26 即可得到偏移后的数字,再将数字 +'A',拼接到字符串 s 即可。
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
string s;
cin >> n;
for (int i = 0; i < 26; i++) {
s += (i+n)%26 + 'A';
}
cout << s;
return 0;
}
202406-2 寻找倍数
题目描述
小杨有一个包含 n 个正整数的序列 A=[a_1,a_2,\dots,a_n],他想知道是否存在 i(1\leq i\leq n) 使得 a_i 是序列 A 中所有数的倍数。
输入格式
第一行包含一个正整数 t,代表测试用例组数。
接下来是 t 组测试用例。对于每组测试用例,一共两行。
其中,第一行包含一个正整数 n;第二行包含 n 个正整数,代表序列 A。
输出格式
对于每组测试用例,如果存在 i(1\leq i\leq n) ,满足对于所有 k(1\leq k\leq n) a_i 是 a_k 的倍数,输出 Yes
,否则输出 No
。
样例输入 1
2
3
1 2 4
5
1 2 3 4 5
样例输出 1
Yes
No
提示
【样例解释】
对于第⼀组数据,对于 a_3=4,满足 a_3 是 a_1 和 a_2 的倍数。
【数据范围】
对于全部数据,保证有 1\leq t\leq 10,1\leq n\leq 10^5,1\leq a_i\leq 10^9。
代码解析
如果有满足条件的数字存在,那么这个数字必然是所有数字中最大的那个数字,所以只需要先找出这组数字中最大的那个,再去试除看能否整除所有数字,使用
flag
做标记。
#include<bits/stdc++.h>
using namespace std;
int main() {
int t, n, a[100005], max_n;
cin >> t;
while (t--) {
cin >> n;
max_n = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
max_n = max(max_n, a[i]);
}
bool flag = true;
for (int i = 0; i < n; i++) {
if (max_n % a[i] != 0) {
flag = false;
break;
}
}
if (flag) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
202403-1 字母求和
题目描述
小杨同学发明了一种新型密码,对于每一个小写英文字母,该小写字母代表了一个正整数,即该字母在字母顺序中的位置,例如字母 a
代表了正整数 1,字母 b
代表了正整数 2;对于每一个大写英文字母,该大写字母代表了一个负整数,即该字母的 ASCII 码的相反数,例如字母 A
代表了负整数 -65。小杨同学利用这种放缩对一个整数进行了加密并得到了一个由大写字母和小写字母组成的字符串,该字符串中每个字母所代表数字的总和即为加密前的整数,例如 aAc
对应的加密前的整数为 1+(-65)+3=-61。
对于给定的字符串,请你计算出它对应的加密前的整数是多少。
输入格式
第一行一个正整数 n,表示字符串中字母的个数。
第二行一个由大写字母和小写字母的字符串 T
,代表加密后得到的字符串。
输出格式
输出一行一个整数,代表加密前的整数。
样例输入 1
3
aAc
样例输出 1
-61
提示
对全部的测试数据,保证 1 \leq n \leq 10^5。
代码解析
小写字母在字母表中的顺序,假设字符
c = 'a'
,只需要c-'a'+1
可得 1
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, sum = 0;
string s;
cin >> n >> s;
for (int i = 0; i < n; i++) {
if (s[i] >= 'a' && s[i] <= 'z')
sum += s[i] - 'a' + 1;
else
sum -= s[i];
}
cout << sum;
return 0;
}
202403-2 完全平方数
题目描述
小杨同学有一个包含 n 个非负整数的序列 A,他想要知道其中有多少对下标组合 <i,j>(1 \leq i < j \leq n),使得 A_i + A_j 是完全平方数。
如果 x 是完全平方数,则存在非负整数 y 使得 y \times y = x。
输入格式
第一行一个非负整数 n,表示非负整数个数。
第二入行包含 n 个非负整数 A_1, A_2, \dots A_n,表示序列 A 包含的非负整数。
输出格式
输出一行一个整数表示答案。
样例输入 1
5
1 4 3 3 5
样例输出 1
3
提示
对全部的测试数据,保证 1 \leq n \leq 1000,0 \leq A_i \leq 10^5。
代码解析
如果
m
不是完全平方数,sqrt(m)
得到的结果是一个浮点数,我们将它向下取整,再次计算平方得到的结果肯定不等于m
#include<iostream>
#include<cmath>
using namespace std;
int main() {
int n, cnt = 0, num[1001];
cin >> n;
for (int i = 0; i < n; i++)
cin >> num[i];
for (int i = 0; i < n-1; i++) {
for (int j = i; j < n; j++) {
int m = num[i] + num[j];
int t = floor(sqrt(m));
if (t * t == m)
cnt++;
}
}
cout << cnt;
return 0;
}
202312-1 小猫分鱼
题目描述
海滩上有一堆鱼,N 只小猫来分。第一只小猫把这堆鱼平均分为 N 份,多了 i<N 个,这只小猫把多的 i 个扔入海中,拿走了一份。第二只小猫接着把剩下的鱼平均分成 N 份,又多了 i 个,小猫同样把多的 i 个扔入海中,拿走了一份。第三、第四、……,第 N 只小猫仍是最终剩下的鱼分成 N 份,扔掉多了的 i 个,并拿走一份。
编写程序,输入小猫的数量 N 以及每次扔到海里的鱼的数量 i,输出海滩上最少的鱼数,使得每只小猫都可吃到鱼。
例如:两只小猫来分鱼 N=2,每次扔掉鱼的数量为 i=1,为了每只小猫都可吃到鱼,可令第二只小猫需要拿走 1 条鱼,则此时待分配的有 3 条鱼。第一只小猫待分配的鱼有 3\times 2+1=7 条。
输入格式
总共 2 行。第一行一个整数 N,第二行一个整数 i。
保证 0<N<10;i<N 。
输出格式
一行一个整数,表示满足要求的海滩上最少的鱼数。
样例输入 1
2
1
样例输出 1
7
样例输入 2
3
1
样例输出 2
25
提示
【样例解释 2】
三只小猫来分鱼 N=3,每次扔掉鱼的数量为 i=1,为了每只小猫都可吃到鱼,可令第三只小猫需要拿走 3 条鱼(拿走 1 条和 2 条不满足要求),则此时待分配的有 10 条鱼。第二只小猫待分配的鱼有 10×3/2+1 = 16 条。第一只小猫待分配的鱼有 16×3/2+1 = 25 条。
代码解析
根据题意倒着往前推即可
#include<bits/stdc++.h>
using namespace std;
bool fish(int i, int j, int n) {
int sum = j;
for (int k = 0; k < n; k++) {
if (k != 0) {
if (sum % (n-1) != 0) {
return false;
}
sum /= (n-1);
}
sum *= n;
sum += i;
}
cout << sum;
return true;
}
int main() {
int n, i, sum;
cin >> n >> i;
for (int j = 1; ; j++) {
if (fish(i, j, n))
break;
}
return 0;
}
202312-2 单位转换
题目描述
小杨这周的数学作业是做单位转换,喜欢编程的小杨决定编程帮他解决这些问题。
小杨只学了长度单位和重量单位,具体来说:
- 长度单位包括千米(
km
)、米(m
)、毫米(mm
),它们之间的关系是:1\text{km} = 1000\text{m} = 1000000\text{mm}。 - 重量单位包括千克(
kg
)、克(g
)、毫克(mg
),它们之间的关系是:1\text{kg} = 1000\text{g} = 1000000\text{mg}。
小杨的作业只涉及将更大的单位转换为更小的单位,也就是说,小杨的作业只会包含如下题型:米转换为毫米,千米转换为毫米,千米转换为米,克转换为毫克,千克转换为毫克,千克转换为克。
现在,请你帮忙完成单位转换的程序。
输入格式
输入的第一行为一个整数,表示题目数量。
接下来 N 行,每行一个字符串,表示转换单位的题目,格式为 x 单位 1 = ? 单位 2。其中,x 为一个不超过 1000 的非负整数, 单位 1 和 单位 2 分别为两个单位的英文缩写,保证它们都是长度单位或都是重量单位,且 单位 1 比 单位 2 更大。
例如,如果题目需要你将 1\text{km} 转换为 \text{mm},则输入为 1 km = ? mm
。
保证 1\le N \le 1000。
输出格式
输出 N 行,依次输出所有题目的答案,输出时,只需要将输入中的 ? 代入答案,其余部分一字不差地输出即可。由于小杨的题目只涉及将更大的单位转换为更小的单位,并且输入的 x 是整数,因此答案一定也是整数。
例如,如果题目需要你将 1\text{km} 转换为 \text{mm},则输入为 1 km = ? mm
。则你需要输出 1 km = 1000000 mm
。
样例输入 1
2
1 km = ? mm
1 m = ? mm
样例输出 1
1 km = 1000000 mm
1 m = 1000 mm
样例输入 2
5
100 m = ? mm
1000 km = ? m
20 kg = ? g
200 g = ? mg
0 kg = ? mg
样例输出 2
100 m = 100000 mm
1000 km = 1000000 m
20 kg = 20000 g
200 g = 200000 mg
0 kg = 0 mg
代码解析
直接使用
cin
输入,避免之后还需要字符串分割,输入的时候可以将 ?和 = 都忽略掉因为题目中说了只能是“大转小”,所以当第一个单位是 m 或者 g 的时候,只能是转到 mm 或者 mg,当第二个单位是 m 或者 g 的时候只能是 km 转 m 或者 kg 转 g,所以这两种可能性都是直接乘 1000,除此之外肯定是 kg 转 mg,或者 km 转 mm
void get(int n, string s1, string s2) {
int m;
if (s1 == "m" || s1 == "g")
m = 1000 * n;
else if (s2 == "m" || s2 == "g")
m = 1000 * n;
else
m = 1000000 * n;
cout << n << ' '+s1+" = " << m << ' '+s2 << endl;
}
观察函数发现代码有些繁琐,而且不管是 m 还是 g,他都是长度为 1 的字符串,所以优化后:
#include<bits/stdc++.h>
using namespace std;
void get(int n, string s1, string s2) {
int m;
if (s1.size() == 1 || s2.size() == 1)
m = 1000 * n;
else
m = 1000000 * n;
cout << n << ' '+s1+" = " << m << ' '+s2 << endl;
}
int main() {
int n;
cin >> n;
while (n--) {
int a;
string s1, s2;
cin >> a >> s1 >> s2 >> s2 >> s2;
get(a, s1, s2);
}
return 0;
}
202309-1 小杨的储蓄
题目描述
小杨共有 N 个储蓄罐,编号从 0 到 N-1。从第 1 天开始,小杨每天都会往存钱罐里存钱。具体来说,第 i 天他会挑选一个存钱罐 a_i,并存入 i 元钱。过了 D 天后,他已经忘记每个储蓄罐里都存了多少钱了,你能帮帮他吗?
输入格式
输入 2 行,第一行两个整数 N,D;第二行 D 个整数,其中第 i 个整数为 {a_i}(保证 0 \le a_i \le N-1)。
每行的各个整数之间用单个空格分隔。
保证 1 \le N \le 1,000;1 \le D \le 1,000。
输出格式
输出 N 个用单个空格隔开的整数,其中第 i 个整数表示编号为 i-1 的存钱罐中有多少钱(i=1, \cdots ,N)。
样例输入 1
2 3
0 1 0
样例输出 1
4 2
样例输入 2
3 5
0 0 0 2 0
样例输出 2
11 0 4
提示
【样例解释 1】
小杨在第 1 天、第 2 天、第 3 天分别向 0 号、 1 号、 0 号存钱罐存了 1 元钱、 2 元钱、 3 元钱,因此 0 号存钱罐有 1+3=4 元钱,而 1 号存钱罐有 2 元钱。
代码解析
第
i
天会给m
号存钱罐投入i
元,所以我们只需要给money[m]
加上i
即可,最后输出的时候注意,下标是从 0 开始的
#include<iostream>
using namespace std;
int main() {
int N, D, money[1001] = {0};
cin >> N >> D;
for (int i = 1; i <= D; i++) {
int m;
cin >> m;
money[m] += i;
}
for (int i = 1; i <= N; i++)
cout << money[i-1] << ' ';
return 0;
}
202309-2 进制判断
题目描述
N 进制数指的是逢 N 进一的计数制。例如,人们日常生活中大多使用十进制计数,而计算机底层则一般使用二进制。除此之外,八进制和十六进制在一些场合也是常用的计数制(十六进制中,一般使用字母 A 至 F 表示十至十五)。
现在有N个数,请你分别判断他们是否可能是二进制、八进制、十进制、十六进制。例如,15A6F
就只可能是十六进制,而 1011
则是四种进制皆有可能。
输入格式
输入的第一行为一个十进制表示的整数 N。接下来 N 行,每行一个字符串,表示需要判断的数。保证所有字符串均由数字和大写字母组成,可能以 0 开头。保证不会出现空行。
保证 1 \le N \le 1000,保证所有字符串长度不超过 10。
输出格式
输出 N 行,每行 4 个数,用空格隔开,分别表示给定的字符串是否可能表示一个二进制数、八进制数、十进制数、十六进制数。使用 1 表示可能,使用 0 表示不可能。
例如,对于只可能是十六进制数的 15A6F
,就需要输出 0 0 0 1
;而对于四者皆有可能的 1011
,则需要输出 1 1 1 1
。
样例输入 1
2
15A6F
1011
样例输出 1
0 0 0 1
1 1 1 1
样例输入 2
4
1234567
12345678
FF
GG
样例输出 2
0 1 1 1
0 0 1 1
0 0 0 1
0 0 0 0
代码解析
可以用笨办法,定义
bool
变量k2, k8, k10, k16
,当遇到不同范围字符,做好标记就可以
#include<iostream>
#include<string>
using namespace std;
void check(string s) {
bool k2=1, k8=1, k10=1, k16=1;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '2' && s[i] <= '9' || s[i] >= 'A')
k2 = 0;
if (s[i] >= '8' && s[i] <= '9' || s[i] >= 'A')
k8 = 0;
if (s[i] >= 'A')
k10 = 0;
if (s[i] >= 'G')
k16 = 0;
}
cout << k2 << ' ' << k8 << ' ' << k10 << ' ' << k16 << endl;
}
int main() {
int n;
cin >> n;
while (n--) {
string s;
cin >> s;
check(s);
}
return 0;
}
202306-1 春游
题目描述
老师带领同学们春游。已知班上有 N 位同学,每位同学有从 0 到 N-1 的唯一编号。到了集合时间,老师确认是否所有同学都到达了集合地点,就让同学们报出自己的编号。到达的同学都会报出自己的编号,不会报出别人的编号,但有的同学很顽皮,会多次报出。你能帮老师找出有哪些同学没有到达吗 ?。
输入格式
输入包含 2 行。第一行包含两个整数 N 和 M,表示班级有 N 位同学,同学们共有 M 次报出编号。约定 2 \le N,M \le 1000。
第二行包含 M 个整数,分别为 M 次报出的编号。约定所有编号是小于 N 的非负整数。
输出格式
输出一行。如果所有同学都到达,则输出 N;否则由小到大输出所有未到达的同学编号,空格分隔。
样例输入 1
3 3
0 2 1
样例输出 1
3
样例输入 2
3 5
0 0 0 0 0
样例输出 2
1 2
代码解析
使用数组来标记已经报过数的同学编号,每次报数
n
,我们就将student[n]
标记为 1需要一个
bool
变量all
来标记是否全部到达
#include<iostream>
using namespace std;
bool student[1001];
int main() {
int N, M, n;
cin >> N >> M;
for (int i = 0; i < M; i++) {
cin >> n;
student[n] = 1;
}
bool all = true;
for (int i = 0; i < N; i++) {
if (!student[i]) {
cout << i << ' ';
all = false;
}
}
if (all) cout << N;
return 0;
}
202306-2 密码合规
题目描述
网站注册需要有用户名和密码,编写程序以检查用户输入密码的有效性。合规的密码应满足以下要求 :。
- 只能由 \texttt a \sim \texttt z 之间 26 个小写字母、\texttt A \sim \texttt Z 之间 26 个大写字母、0 \sim 9 之间 10 个数字以及
!@#$
四个特殊字符构成。 - 密码最短长度 :6 个字符,密码最大长度 :12 个字符。
- 大写字母,小写字母和数字必须至少有其中两种,以及至少有四个特殊字符中的一个。
输入格式
输入一行不含空格的字符串。约定长度不超过 100。该字符串被英文逗号分隔为多段,作为多组被检测密码。
输出格式
输出若干行,每行输出一组合规的密码。输出顺序以输入先后为序,即先输入则先输出。
样例输入 1
seHJ12!@,sjdkffH$123,sdf!@&12HDHa!,123&^YUhg@!
样例输出 1
seHJ12!@
sjdkffH$123
提示
【样例 1 解释】
输入被英文逗号分为了四组被检测密码:seHJ12!@
、sjdkffH$123
、sdf!@&12HDHa!
、123&^YUhg@!
。其中 sdf!@&12HDHa!
长度超过 12 个字符,不合规;123&^YUhg@!
包含四个特殊字符之外的字符不合规。
代码解析
定义
check
函数来判断一个密码是否合规
check
函数中,定义up, down, digit, chr
四个bool
变量分别判断字符串中是否含有大写、小写、数字、特殊符号,遍历的过程中如果有就标记为1
,当全部遍历完成之后判断up + low + digit >= 2
表示三个中至少有两个,再判断chr
是否为真就可以拼接分割密码的时候,注意最后一个密码不是以逗号
,
结尾的,所以最后需要再判断一下
#include<iostream>
#include<string>
using namespace std;
bool check(string s) {
bool up = 0, low = 0, digit = 0, chr = 0;
if (s.size() < 6 || s.size() > 12)
return false;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= 'a' && s[i] <= 'z')
low = 1;
else if (s[i] >= 'A' && s[i] <= 'Z')
up = 1;
else if (s[i] >= '0' && s[i] <= '9')
digit = 1;
else if (s[i]=='!'||s[i]=='@'||s[i]=='#'||s[i]=='$')
chr = 1;
else
return false;
}
if (up + low + digit >= 2 && chr)
return true;
else
return false;
}
int main() {
string s, password = "";
cin >> s;
for (int i = 0; i < s.size(); i++) {
if (s[i] == ',') {
if (check(password))
cout << password << endl;
password = "";
} else {
password += s[i];
}
}
if (check(password))
cout << password << endl;
return 0;
}