ACM 24届新生第二次周赛题解

        算是第一次正式赛吧看看实力,国庆期间有一部分没留校的没打第一次,这次还有好多一直不会但是都在拖着不学的,一看真要到考察实力了不敢来了,从第一节课开始就强调了自学,对此很难评,只能说赶紧选择到底要不要打竞赛吧,没有自学能力及自控力的感觉不适合的话就不要浪费时间了,本次及格线6题,难度大概与前三场招新赛相当(或略低),前排同学应该补题到9~10道,中游应该7~8道

难度分布

签到:1,5,11

简单:4,6,7

中等:2,9,10

困难:3,8

题解:

1,这是第一题

本题要求对一组给定的整数或小数进行四舍五入操作。题目的输入范围可以包含很大的数字(最高到 1𝑒12),因此在处理时需要数据类型选择。

四舍五入的基本规则是:

如果小数部分大于等于 0.5,向上取整; 如果小数部分小于 0.5,向下取整。

#include <iostream>
using namespace std;
typedef long long ll;
​
int main() {
    int N;
    cin >> N;  // 读取数据组数
    for (int i = 1; i <= N; i++) 
    {
        double X;
        cin >> X;  // 读取每个数X
        ll rounded;
        
        // 手动实现四舍五入
        if (X - ll(X) >= 0.5) {
            rounded = ll(X) + 1;  // 小数部分 >= 0.5,向上取整
        } else {
            rounded = ll(X);  // 小数部分 < 0.5,向下取整                                                                                                                                                                                                                                                                                                                                            //土豆片最帅!!!
        }
        
        cout << rounded << endl;  // 输出结果
    }
    
    return 0;
}

2,小钱钱,真心甜!!!

很显然,搞个结构体和sort排序就可以了

#include<bits/stdc++.h>
​
using namespace std;
struct node {
    string xm; //姓名
    int qm, bj; //期末平均成绩,班级评议成绩
    char bgb, xb; //是否是学生干部,是否是西部省份学生
    int lw; //发表的论文数
    int ans; //个人所获的奖金数
    int sum; //序号数,因为题目要求两个人所获的奖金数相同时,输出先出现的,即序号较靠前的(较小的)
}
a[101];
​
​
bool cmp(node x, node y) {
    if (x.ans == y.ans) {
        return x.sum < y.sum;
    } else {
        return x.ans > y.ans;
    } //奖学金数从大到小排序,相同时按序号数从小到大排序
}
​
int main() {
    int n, tot=0;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        
        cin >> a[i].xm >> a[i].qm >> a[i].bj >> a[i].bgb >> a[i].xb >> a[i].lw;
        
        if (a[i].qm > 80 && a[i].lw >= 1) {
            a[i].ans += 8000;
        }
        if (a[i].qm > 85 && a[i].bj > 80) {
            a[i].ans += 4000;
        }
        if (a[i].qm > 90) {
            a[i].ans += 2000;
        }
        if (a[i].xb == 'Y' && a[i].qm > 85) {
            a[i].ans += 1000;
        }
        if (a[i].bj > 80 && a[i].bgb == 'Y') {
            a[i].ans += 850;
        }
        a[i].sum = i;
        tot += a[i].ans; //tot为总的奖学金数
    }
    sort(a + 1, a + n + 1, cmp);
    
    cout << a[1].xm << endl << a[1].ans << endl << tot;                                                                                                                                                                                                                                                                                                                                                                         //土豆片最帅!!!
    
}

3,似曾相识,难道是签到?

这个题和上次培训时出的"555"的区别是,这道题中的"1314"可以不连续,而"555"是需要连续的.这个题的难点也在这里,如何判断一个数中是否含有不连续的"1314". 我们仍然需要先进行数位拆解,然后来判断,这里着重讲一下判断的代码

这部分代码是查找数字 o 是否包含子序列"1314"。 pos 代表从哪个位置开始检查。tmppos 用来遍历数字 o 的每一位,寻找 a[] 中的子序列 1, 3, 1, 4。 外层循环遍历 a[] 数组(即 "1314"),内层循环在数字的位数组 numm[] 中查找对应的数字。 如果找到完整的 "1314"(find == 4),则将标志位 f 置为1,表示当前数字包含子序列"1314"。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10000;
int pre[N];
void init(){
    int a[] = { 0,1,3,1,4 };
    for (int o = 1314; o <= N; o++) {
        int num = 0;
        int tmp = o;
        while (tmp) {
            tmp /= 10;
            num++;
        }
        int numm[num + 1];
        int idx = num;
        tmp = o;
        while (tmp) {
            numm[idx] = tmp % 10;
            tmp /= 10;
            idx--;
        }
        int f = 0;
        int pos=1;
        while(pos!=num){
            int tmppos=pos;
            int find=0;
            for(int i=1;i<=4;i++){
                for(int j=tmppos;j<=num;j++){
                    if(a[i]==numm[j]){
                        find++;
                        tmppos=j+1;
                        break;
                    }
                }
            }
            if(find==4)f=1;
            pos++;
        }
        
        if (f){    
            pre[o] = 1;
        }
    }
    for (int i = 1; i <= N; i++){
        pre[i] = pre[i -1 ] + pre[i];
    } 
}
int main() {
    int t=100;
    scanf("%d",&t);
    init();
    while(t--){
        int n;
        scanf("%d",&n);
        printf("%d\n",pre[n]);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      //土豆片最帅!!!                                                                                                                                                          
    }
}
 

4,来喂猫猫

我们只要把从第二个数据到最后一个数据从小到大排序,计算一下前缀和,然后for循环遍历即可

#include<bits/stdc++.h>
using namespace std;
#define int long long
int a[1000009];
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);

    int n,m,ans=0;
    cin>>n>>m;
    for(int i=1;i<=m;i++)cin>>a[i];
    sort(a+2,a+1+m);
    for(int i=1;i<=m;i++){
        a[i]=a[i]+a[i-1];
    }
    for(int i=1;i<=m;i++){
        if(a[i]>n){
            ans=i-1;
            break;
        }
    }
    cout<<ans<<endl;                                                                                                                                                                                                                                                                                                                                    //土豆片最帅!!!
}

5,签到?

简单的判断是使用“+”还是“-”

​
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
signed main()
{
    int t;
    cin>>t;
    while(t--)
    {
        int a,b,c;
        cin>>a>>b>>c;
        if(a+b==c) cout<<"+";
        else cout<<"-";
        cout<<endl;                                                                                                                                                                                                                                                                                                                                                                                                                                         //土豆片最帅!!!
    }
    return 0;
}

6,小小博弈

在每轮游戏中,当前的玩家都会拿走一个球。如果你拿走双方都可以取的球,那么对手就会少一个可以拿的球。因为每个玩家都想在自己拿完可以拿的球之前让对手没球可拿,所以只要有一个双方都可以拿的球,他们就会拿双方都可以拿的球。

#include<stdio.h>
​
void solve()
{
    int a,b,c;
    scanf("%d%d%d",&a,&b,&c);
    if(a+c%2>b)printf("First\n");
    else printf("Second\n");
}
int main()
{
    int t=1;
    scanf("%d",&t);
    while(t--)
    {
        solve();                                                                                                                                                                                                                                                                                                                                //土豆片最帅!!!
    }
    return 0;
}
​

7,不是,又是数学!!?

题目要求:求跨越n个宇宙所需最少硬币数 已知一个宇宙需要收费a硬币,优惠策略下两个宇宙需要b硬币,那么比较2a和b的价格,

(1)如果2a小于b则不选择营销策略去跨越宇宙,此情况最优解为n * a (2)如果2a大于b则选择营销策略去跨越宇宙,但需要注意可能存在余的情况,分为两部分n/2和n%2,则结果为(n/2)b+(n%2)a (3)如果2a等于b,则选择n*a即可

#include<stdio.h>
​
int main() 
{
    int t;
    scanf("%d",&t); // 输入测试用例数量
    while(t--) 
    {
        int n,a,b;
        scanf("%d %d %d",&n,&a,&b); // 输入宇宙数量,单独价格,促销组合价格
        // 如果营销价比正常价划算,则尽可能多地使用营销价
        if(b<a*2) 
        {
            int c=n/2,d=n%2; // 计算营销组合购买的数量和单独购买的数量
            printf("%d\n",c*b+d*a); // 输出最小花费
        } 
        else 
        {
            printf("%d\n",n*a); // 否则,直接单独购买                                                                                                                                                                                                                                                                                                                                                                            土豆片最帅!!!
        }
    }
    return 0;
}

8,博士,你不许玩维什戴尔!!!

题意:给你一个长度不大于1000的01字符串你进行如下操作,把0变为1或把1变为0,问最少能用几次操作让改字符串子串不含010和101. 由题意可知,字符串的最终状态一共可以分为4类: 全是1(1111) 全是0(0000) 左0右1(0011) 左1右0(1100) 前两种我们只需统计0和1的数量就可以求出变到该状态需要操作的次数。 后两种我们可以先用for循环对数组进行预处理,我们造两个数组a和b分别储存当前位置以及当前位置之前0的总数和1的总数,在此for循化中我们也需要顺便把整个字符串1的个数和0个个数记录(sum0,sum1)。 然后我们再跑一个for循换,每次遍历都把当前位置作为01分界处或者10分界处,当左0后1时我们的操作数就是当前位置之前的1的个数(b[i])加上当前位置之后0的个数(sum0-a【i】)左1右0同理。时间复杂度为O(n)。

#include<bits/stdc++.h>
const int N = 1e3 + 10;
int a[N], b[N];
char s[N];
int min(int x, int y) {
    if (x < y) return x;
    else return y;
}
int main() {
    int o;
    scanf("%d", & o);
    while (o--) {
        scanf("%s", s);
        int n = strlen(s);
        int sum0 = 0, sum1 = 0;
        for (int i = 0; i < n; i++) {
            if (s[i] == '0') sum0++;
            else sum1++;
            a[i] = sum0;
            b[i] = sum1;
        }
        int minn = min(sum0, sum1);
        for (int i = 0; i < n; i++) {
            minn = min(minn, a[i] + sum1 - b[i]);
            minn = min(minn, b[i] + sum0 - a[i]);
        }   
        printf("%d\n", minn);                                                                                                                                                                                                                                                                                                                               //土豆片最帅!!!
    }
}

9,周可儿的面具存放柜

首先题目意思是给一串已经排好了的数字问你某个数字的位置。 如果从1到n扫一遍的话肯定超时。 所以这里用了二分的方法:

首先找到这串数字中间位置的那个数,然后与需要查询的数比较

如果要查询的数小于等于中间那个数,那么答案肯定在左边

如果要查询的数大于中间那个数,那么答案肯定在右边

如此重复,直到要查询的区域变为1,也就是l,r相等。

#include <stdio.h>
​
int a[1000010];
​
int main () {
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i = 1; i <= n; i++){
        scanf("%d", &a[i]);
    }
    while (m--) {
        int x;
        scanf("%d",&x);
        int l = 1, r = n;
        while (l < r) {
            int mid = (l + r) >> 1;
            if (a[mid] >= x) r = mid;
            else l = mid + 1;
        }
        if (a[l] == x) {
            printf("%d ", l);
        } else {
            printf("-1 ");                                                                                                                                                                                                                                                                                                                                                                                  //土豆片最帅!!!
        }
    }
}

10,距离(easy*easy)

一个点在两个端点中间时,该点分别到两个端点的距离之和最短。 端点需要排序后首尾成对出现,所以直接输出处于数据中间的数字,分奇偶讨论,奇数直接输出最中间的数,偶数输出中间两个数之间的数。 冒泡排序会超时,用桶排。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e8 + 5;
int a[N], b[N];
​
int main() 
{
    int n, id;
    cin >> n;
    int mmax = 0;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        b[a[i]]++;//统计个数
        mmax = max(a[i], mmax);//找边界
    }
    
    int cnt = 1;
    for (int i = 1; i <= mmax; i++)
    {
        while (b[i]--)//桶排
        {
            a[cnt++] = i;
        }
    }
    
    if (n % 2 != 0) {
        id = n / 2 + 1;
        cout << a[id] << endl;
    }
    else if (n % 2 == 0) {
        cout << (a[n / 2] + a[n / 2 + 1]) / 2 << endl;                                                                                                                                                                                                                                                                                                      //土豆片最帅!!!
    }
    return 0;
}

11,土豆片爱说反话

输入一个字符串,然后倒序输出即可

#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
​
void bluechips(){
    int n;
    cin>>n;
    string s;
    cin>>s;
    for(int i=n-1;i>=0;i--){
        cout<<s[i];
    }
}
​
signed main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int t=1;
//  cin>>t;
    while(t--){
        bluechips();                                                                                                                                                                                                                                                                                                                            //土豆片最帅!!!
    }
    return 0;
}

ACM/ICPC(ACM International Collegiate Programming Contest, 国际大学生程序设计竞赛)是由国际计算机界历史悠久、颇具权威性的组织ACM(Association for Computing Machinery,国际计算机协会)主办的,世界上公认的规模最大、水平最高的国际大学生程序设计竞赛,其目的旨在使大学生运用计算机来充分展示自己分析问题和解决问题的能力。该项竞赛从1970年举办至今已历29,一直受到国际各知名大学的重视,并受到全世界各著名计算机公司的高度关注,在过去十几年中,APPLE、AT&T、MICROSOFT和IBM等世界著名信息企业分别担任了竞赛的赞助商。可以说,ACM国际大学生程序设计竞赛已成为世界各国大学生最具影响力的国际级计算机类的赛事,是广大爱好计算机编程的大学生展示才华的舞台,是著名大学计算机教育成果的直接体现,是信息企业与世界顶尖计算机人才对话的最好机会。   该项竞赛分区域预赛和国际决赛两个阶段进行,各预赛区第一名自动获得参加世界决赛的资格,世界决赛安排在每年的3~4月举行,而区域预赛安排在上一年的9~12月在各大洲举行。   ACM/ICPC的区域预赛是规模很大、范围很广的赛事。仅在2003年参加区域预赛的队伍就有来自75个国家(地区),1411所大学的3150支代表队,他们分别在127个赛场中进行比赛,以争夺全球总决赛的73个名额,其激烈程度可想而知。 2005年第30ACM/ICPC亚洲赛区预赛共设了北京、成都、汉城、东京等11个赛站,来自亚洲各国知名高校的各个代表队进行了激烈的角逐。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bluechips·zhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值