官方题解 | 第三届飞翔杯基础组
2025-06-14 18:05:32
发布于:浙江
官方题解 | 【基础组】ACGO“飞翔杯”第三届季度赛
赛纲介绍
本次题目的总体题目难度如下,各位选手可以借此评估一下自身的技术水平
题目编号 | 题目名称 | 题目难度 |
---|---|---|
T1 | 求和 | 入门 |
T2 | 字符串价值 | 入门 |
T3 | 数位和 | 入门 |
T4 | 减少荒地开垦 | 普及- |
T1 求和
题目大意
在长度求所有末尾数字是 或者 的数字的总和。
题解思路
所有末尾数字是 或者 的数字 ,都是 的倍数。因此可以直接循环遍历整个数组, 计算所有可以整除 的数字的总和即可。(数据范围较大,记得开 。
参考代码
#include<bits/stdc++.h>
using namespace std;
int main(){
long long sum = 0;
int n;
cin >> n;
for(int i = 1; i <= n; i++) {
int x;
cin >> x;
if(x % 5 == 0) sum += x; //末尾是0或者5的数字 都会被5整除
}
cout << sum << endl;
}
T2 字符串价值
题目大意
字符串价值的定义是 每种字母的出现次数 该字母的 码值。 求给定字符串的字符串价值。
题解思路
读入字符串之后,直接循环遍历,计算一下每种字母出现的次数并且存储在桶数组中。
最终按照字符串价值的定义计算答案。
参考代码
#include<bits/stdc++.h>
using namespace std;
int cnt[150]; //桶数组 由于本份代码直接使用ASCII码值作为下标 因此空间需要开大一些到150
int main()
{
string s;
cin >> s;
for(int i = 0; i < s.size(); i++) cnt[s[i]]++; //直接使用ASCII码值作为下标
long long ans = 0;
for(int i = 'a'; i <= 'z'; i++) { //循环遍历时候也直接用字符的值作为遍历范围。
ans += cnt[i] * i;
}
cout << ans << endl;
return 0;
}
T3 数位和
题目大意
给定两个日期 和, 请计算两个日期之间的所有日期里,一共有多少种不同的数位和。
例如:2024-12-01 和 2024-11-02 数位和相同都是 。
题解思路
本题需要考虑的内容较多:
对于单个日期求数位和, 需要将 年, 月, 日,分别计算数位和再求和。
为了从日期 遍历到 日期 , 需要每次手动求一下第二天的日期是多少
当本月已经来到最后一天,则要到下一个月的第一天, 如果本月是今年的最后一个月, 则要到第二年的 月 日。
对于整个范围内所有的日期, 计算数位和之后在桶数组中标记该数字出现过。最后遍历桶数组统计不同数位和出现的次数就好。
为了计算第二天的日期,比较方便的方法是开一个数组存储一下每个月有多少天。 但是二月份需要特殊判断,需要先判断是否是闰年才能决定二月份的天数是 还是 天。
参考代码
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6+10;
int month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
bool ck(int x) { //闰年判断 检测是否是闰年从而判断2月有几天
if(x % 4 == 0 && x % 100 || x % 400 == 0) return true;
return false;
}
int S(int a, int b, int c) { // 对于 a年 b月 c日 求一下数位和。
int sum = 0;
while(a) {
sum += a % 10;
a /= 10;
}
while(b) {
sum += b % 10;
b /= 10;
}
while(c) {
sum += c % 10;
c /= 10;
}
return sum;
}
int x[1010]; //桶数组 存储每种数字是否出现过
int main(){
int a, b, c, d, e, f;
cin >> a >> b >> c >> d >> e >> f;
while(a != d || b != e || c != f) { //在到达日期B之前 一直循环。
x[S(a, b, c)] = 1;
int M = month[b];
if(b == 2 && ck(a)) M = 29;
c++;
if(c > M) {
c = 1;
b++;
}
if(b > 12) {
b = 1;
a++;
}
}
x[S(d, e, f)] = 1; //日期B也需要计算一下
int ans = 0;
for(int i = 1; i <= 1000; i++) if(x[i]) ans++; //直接遍历桶数组 每有一个数字出现过, 则答案+1
cout << ans << endl;
}
T4 减少荒地开垦
题目大意
在一片 的田地中, '.' 代表荒地, '#' 代表杂物。一片空地如果四周都没有杂物则可以开垦。
小明为了尽可能减少开垦的数量, 因此他决定往田里放一个杂物,求最终的最少开垦数量。
题解思路
是否可以开垦取决于周边的杂物数量, 因此我们可以先计算一下,没有放置杂物的情况下,能够开垦的土地数量。
我们可以对于每一个位置 ,分别判断一下上下左右是不是杂物,统计一下该点周边杂物的数量存储到 。如果杂物数量为, 并且该点是一块荒地,则初始可以开垦的数量 。
为了获取最终的最少开垦数量, 我们需要求放一个杂物之后可以减少的最大可开垦荒地数量 ,显然我们只会把杂物放在荒地上。
对于所有的荒地,我们求一下把杂物放在上面之后能够减少的可开垦荒地数量,并且求取最大值即为我们的目标。
当对一块荒地放上杂物之后会带来的影响有: 四周的荒地如果原先可以开垦, 则现在不可以开垦了,减少的数量 + 1。 而这块荒地本身,如果原先也是可以开垦的( ),则减少的数量 + 1。
参考代码
#include <bits/stdc++.h>
using namespace std;
int n, m;
char a[1010][1010]; //二维字符数组存储田地信息
int cnt[1010][1010];//记录周边杂物数量
int dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0}; //使用方向数组 方便遍历上下左右四个格子
int main() {
cin >> n >> m;
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= m; j++) cin >> a[i][j];
}
int ans = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++) {
for(int k = 0; k < 4; k++){
int ni = i + dx[k], nj = j + dy[k];
if(a[ni][nj] == '#') cnt[i][j]++; //记录周边杂物数量
}
if(cnt[i][j] == 0 && a[i][j] == '.') ans++; //周边无杂物且这是一块荒地, 则初始可开垦数量 +1
}
int sub = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++) {
if(a[i][j] == '#') continue;
int res = 0;
for(int k = 0; k < 4; k++) {
int ni = i + dx[k], nj = j + dy[k];
if(ni >= 1 && ni <= n && nj >= 1 && nj <= m && a[ni][nj] == '.' && cnt[ni][nj] == 0) res++;
} //周边如果是荒地 且原先可以开垦 那么就是可以减少的开垦数量
if(cnt[i][j] == 0) res++;
sub = max(sub, res); //更新可以减少的最大值
}
cout << ans - sub << endl; //初始数量 - 减少的数量 即为答案
}
全部评论 2
T2 std 是不是错了,没有考虑到大写字母的情况 awa(?)
10小时前 来自 浙江
012小时前 来自 重庆
0
有帮助,赞一个