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
2025-08-27 来自 浙江
0@AC君 给个置顶或精选呗
2025-08-26 来自 浙江
0欢乐赛题解一般不会给精选,但会置顶
2025-08-26 来自 上海
0好的,谢谢
2025-08-27 来自 浙江
0













有帮助,赞一个