ACGO欢乐赛#54|非官方题解
2025-08-28 16:20:18
发布于:浙江
非官方题解哦,官方题解
比赛题目
T1.作业计划
知识点:输入输出,向上取整(ceil)
题目:
阿北端午节作业补到了晚上十二点才补完,这次暑假他决定痛(he)改(li)前(ji)非(hua),确保不会再需要一晚上的奇迹。
阿北这次的暑假作业本上分了总共 50 天的作业,完成每天的作业需要 x 小时。阿北计划 30 天完成,他需要你帮他算一算每天至少要用多少小时来写作业。
简化:
阿北分了总共 50 天来完成作业,完成每天的作业需要 x 小时。阿北计划 30 天完成,那么他每天至少要用多少小时来写作业。
俺的方法:
看题目,就是将 50天,每天x小时 转成 30天,每天 n 小时 ,然后求n。
那么 n 该怎么求呢?其实就是用需要用的总时间/天数,也就是(记得向上取整)
#include<bits/stdc++.h>
using namespace std;
int main(){
int x;
cin >> x;
cout << ceil(50.0 * x / 30.0);
return 0;
}
T2.扑克积分
知识点:多重单分支
题目:
阿北最近喜欢玩一个扑克积分的游戏,规则是抽 4 张扑克牌,牌面点数 1∼15 表示 1∼10 和 JQK 以及小王大王,每张牌的牌面点数都有对应的积分。其中 3∼13 的积分为牌面点数,1 的积分为 15,2 的积分为 16,14 的积分为 20,15 的积分为 25。总得分为四张牌的积分总和。
特别的,如果四张牌的牌面点数都相同则称为炸弹,总积分为原积分的五倍。如果同时拥有小王和大王则称为王炸,总积分为原积分再加上 160 分。牌堆中其他牌面点数的牌都有 4 张,但 14∼15 只有各一张。
简化:
可以借助表格
扑克牌点数 | 积分 |
---|---|
1(A) | 15 |
2 | 16 |
3 | 3 |
4 | 4 |
5 | 5 |
6 | 6 |
7 | 7 |
8 | 8 |
9 | 9 |
10 | 10 |
11(J) | 11 |
12(Q) | 12 |
13(K) | 13 |
14(小王) | 20 |
15(大王) | 25 |
特别的:
- 当a = b = c = d时,积分*5,
- 当{a,b,c,d}中同时有{14,15}时,积分+160(如果你上了高中,你也可以理解A = {a,b,c,d},B = {14,15},然后呢B∈A(B是A的子集))
俺的方法:
就是先直接加,在特判
#include<bits/stdc++.h>
using namespace std;
int main(){
int a,b,c,d;
cin >> a >> b >> c >> d;
int f[20];
f[1] = 15,f[2] = 16,f[3] = 3,f[4] = 4,f[5] = 5,f[6] = 6,f[7] = 7,f[8] = 8,f[9] = 9,f[10] = 10,f[11] = 11,f[12] = 12,f[13] = 13,f[14] = 20,f[15] = 25;
long long ans = (long long)(f[a] + f[b] + f[c] + f[d]);
if(a == b && b == c && c == d) ans *= 5;
if((a == 14 || b == 14 || c == 14 ||d == 14) && (a == 15 || b == 15 || c == 15 || d == 15)) ans += 160;
cout << ans;
return 0;
}
T3.配装选择
知识点:循环
题目:
阿北给自己的游戏角色选择了一套主堆暴击和暴击伤害的装备套装,但是看着加成改装件不同的数值,阿北需要你帮他选择一个能使预期伤害最高的改装件。
基础伤害为 10000,预期伤害为 基础伤害暴击率(100%+暴击伤害加成)+基础伤害*(100%-暴击率)*100%。其中暴击率的有效上限为 100%,x%=1.0×x÷100。
装备套装穿上后阿北的暴击率为 x%,暴击伤害加成为 y%。阿北有 n 件属性合适的改装件,这些改装件分别能增加 a% 的暴击率和 b% 的暴击伤害。
一般暴击率超出 100% 后就没有作用了,但阿北的装备套装效果能够使超出 100% 暴击率的部分转化为 300% 的暴击伤害加成。阿北需要你帮他选出一件能够使预期伤害最高的改装件,他想知道最高的预期伤害是多少。
简化:
重点在于 预期伤害为:基础伤害*暴击率*(100%+暴击伤害加成)+基础伤害*(100%-暴击率)*100%
简化会吧:
基础伤害*暴击率*(100%+暴击伤害加成)+基础伤害*(100%-暴击率)*100%
=基础伤害*[暴击率*(100%+暴击伤害加成)+(100%-暴击率)*100%]
=基础伤害*[暴击率*(1+暴击伤害加成)+(1-暴击率)*1]
=基础伤害*[暴击率*(1+暴击伤害加成)+(1-暴击率)]
俺的方法:
就用基础伤害*[暴击率*(1+暴击伤害加成)+(1-暴击率)]
这个公式算!
#include<bits/stdc++.h>
using namespace std;
int main() {
long long n, x, y;
cin >> n >> x >> y;
double ans = 0.0;
for (int i = 0; i < n; ++i) {
long long a, b;
cin >> a >> b;
double jcsh = 10000; //基础伤害
double bjl = min((x + a) / 100.0 , 1.0); //暴击率
double bjshjc = ((y + b) / 100.0) + max(((x + a) / 100.0 - 1.0), 0.0) * 3.0; // 暴击伤害加成
double sum = jcsh * (bjl * (1.0 + bjshjc) + (1.0 - bjl));
ans = max(sum,ans);
}
cout << ans << endl;
return 0;
}
T4.LP统计
知识点:循环和数组
题目:
又到了暑假参加实践活动的时候,阿北和同学们需要通过参加社区活动来积攒 LP(出勤积分)。往年社区都是到最后人工统计所有同学的 LP,今年社区希望阿北能开发一个自动统计 LP 的程序,能够统计出每位同学对应的 LP。
社区记录的出勤名单是一个字符串,记录了整个假期所有活动的签到情况,人名之间有空格隔开。每个人可能参加了多个社区活动,所以可能存在多次签名记录。每一个签名将会增加 1 点 LP。
社区希望这个程序能够统计每个人的 LP 情况,并按人名出现的顺序输出每个人的 LP 情况。
简化:
就是统计每个人的出现次数(输入的最后一个0除外)
俺的方法:
利用map和vector来做,vector记录所有人的名字,map记录出现次数
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
vector<string> ve;
map<string, int> lp;
while (cin >> s) {
if(s == "0") break;
if (lp.find(s) == lp.end()) {
ve.push_back(s);
lp[s] = 1;
} else {
lp[s]++;
}
}
for (int i = 0;i < ve.size();i++) {
cout << ve[i] << " " << lp[ve[i]] << endl;
}
return 0;
}
实在不会,你暴力查找也能过:
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
vector<string> ve;
while(cin >> s) if(s != "0") ve.push_back(s);
map<string,bool> m;
for(int i = 0;i < ve.size();i++){
if(m[ve[i]] == false){
m[ve[i]] = true;
int ans = 0;
for(int j = i;j < ve.size();j++){
if(ve[i] == ve[j]) ans++;
}
cout << ve[i] << " " << ans << endl;
}
}
return 0;
}
T5.晨会列队
知识点:个人认为是循环和排序
题目:
老师们虽然每年都说一届不如一届了,但这一届新生的晨会排队确实是让阿北都有点吓到了,虽然每个班都排好了队伍,但是各班的队伍都是高低起伏。
好在晨会还没有开始,请你和阿北一起把晨会的队伍重新排列好,让每个班都按照身高前面低后面高的顺序排列。
简化:
按列排序。
俺的方法:
输入时就把列"变成"行,输出相反,然后利用vector来读取每一行,然后排序。
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
int a[105][105];
memset(a, 0, sizeof(a));
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
int x;
cin >> x;
if(x != 0) a[j][i] = x;
}
}
for(int i = 0; i < m; i++) {
vector<int> t;
for(int j = 0; j < n; j++) {
if(a[i][j] != 0) t.push_back(a[i][j]);
}
sort(t.begin(), t.end());
int idx = 0;
for(int j = 0; j < n; j++) {
if(a[i][j] != 0) a[i][j] = t[idx++];
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
printf("%4d", a[j][i]);
}
cout << endl;
}
return 0;
}
实在不会,你暴力冒泡排序也能过:
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
int a[105][105];
memset(a, 0, sizeof(a));
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
int x;
cin >> x;
if(x != 0) a[j][i] = x;
}
}
for(int i = 0; i < m; i++){
for(int k = 0; k < n; k++){
for(int j = 0; j < n - 1 - k; j++){
if(a[i][j] != 0 && a[i][j + 1] != 0 && a[i][j] > a[i][j + 1])
swap(a[i][j], a[i][j + 1]);
}
}
}
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
printf("%4d", a[j][i]);
}
cout << endl;
}
return 0;
}
T6.翻转
知识点:枚举
题目:
给出一个 01 串,要求必须将其中的一个 1 翻转为 0 。
统计翻转后串中连续的 0 的个数,将所有连续的 0 的个数相乘,阿北想知道这个乘积最小是多少。
俺的方法:
枚举,将每一个1试着翻转然后获取最小值,不过没想到,没超时!
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
cin >> s;
long long minn = LLONG_MAX;
for(int i = 0;i < s.size();i++){
if(s[i] == '1'){
s[i] = '0';
long long ans = 1, sum = 0;
for(int j = 0;j < s.size();j++){
if(s[j] == '1'){
if(sum > 0){
ans *= sum;
sum = 0;
}
} else {
sum++;
}
}
if(sum > 0){
ans *= sum;
}
minn = min(minn, ans);
s[i] = '1';
}
}
cout << minn;
return 0;
}
对你有帮助吗?能给我一个小赞嘛?有问题快说!
恭喜你完成了所有题目!太棒啦!我祝大家每题AC!大家一起加油!
打个广告吧!
拜拜!
@AC君,虽然是非官方题解,但还是求个顶吧!
全部评论 2
ddd
1周前 来自 浙江
0@AC君 给个置顶或精选呗
1周前 来自 浙江
0欢乐赛题解一般不会给精选,但会置顶
1周前 来自 上海
0好的,谢谢
1周前 来自 浙江
0
有帮助,赞一个