2022湘南ACM协会技术部新生选拔赛题解

话不多说,直接进入正题!


E、苹果采购:

题目大意:

        给n个同学每个同学a个苹果,已知n个a,问至少要多少个苹果才够。

题解:

        这题属签到题,非常简单,也没有卡int数据范围,只是要注意一下多组输入的问题就可以了。

#include <stdio.h>

int main()
{
    int n, m;
    while(~scanf("%d%d", &n, &m))
        printf("%d\n", n*m);
    
    return 0;
}

G、迟到的猴子

题目大意:

        一共有100只猴子,每个猴子都有自己的编号1-100,其中只有n只猴子到场了,问 没到场的猴子中编号最小的是几号。

题解:

        因为每个猴子的编号是唯一的,所以我们只需要开一个110的数组a[110],使其初始值为0,在输入到场的猴子的编号,设第 i 只猴子的编号是xx, 则令a[xx] = 1,最后将编号从1枚举到100, 若a[i] == 0,则说明这只猴子没到场,输出该编号 i 即可。

#include <stdio.h>

int n, a[110] = {0};
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
    {
        int xx; scanf("%d", &xx);
        a[xx] = 1;
    }
    
    for(int i = 1; i <= 100; i ++)
        if(a[i] == 0)
        {
            printf("%d\n",i);
            break;
        }
    return 0;
}

A、选举

题目大意:

        有三个人参加选举,分别是a,b,c票;问 这三个人各自至少要再得多少票才能使自己的票数变得最高。

题解:

        首先用一个数组将三个人的得票存起来,再建一个数组存答案;用两重循环将每两两相差的票算出来,记录两两相差中最大的差距。(注意:当两重循环两两比较遇到同一个人时,可以直接跳)

#include <stdio.h>
int main()
{
    int a[3], ans[3];
    while (~scanf("%d%d%d", a, a + 1, a + 2))
    {
        ans[0] = ans[1] = ans [2] = 0;
        
        for (int i = 0; i < 3; i ++)
            for (int j = 0; j < 3; j ++)
            {
                if(i == j)  continue;
                if(a[j] - a[i] >= ans[i])   ans[i] = a[j] - a[i] + 1;
            }
            
        printf("%d %d %d\n", ans[0], ans[1], ans[2]);
    }
    return 0;
}

B、吃羊问题

题目大意:

        岛上有若干只虎和一只羊,所有老虎都想吃羊,但是吃了羊之后自己就会变成羊,当然老虎也可以选择吃草,问 当岛上有n只虎时,羊会不会被吃,会就输出Yes,不会则输出No

题解:

        典型的逻辑思维题,可以很明确的说 当n为偶数时,羊不会被吃,当n为奇数时,羊就会被吃;

        为什么?先模拟一遍,只有一只虎时,那他可以毫不犹豫的选择把羊吃了;当虎变成两只时,他们俩都不敢妄动,因为只要其中一只吃了羊,就会变成羊,另一只也会毫不犹豫把它吃了,以此类推,三四五只羊都是这样的,所以这就转变成了一个关于奇偶的问题。(注意:n的数据范围是[1, 1e18), 所以n的数据类型要开long long);

#include <stdio.h>

int main()
{
    long long n;
    while(~scanf("%lld", &n))
        if(n % 2)   puts("YES");
        else    puts("NO");
    
    return 0;
}

C、教练,我要打ACM

题目大意:

        在桌子上有n颗瓜子,XX老师和DD老师可以一次拿1-3颗,谁拿到最后一颗瓜子谁就获胜,DD老师先拿,问 在两人都足够聪明的情况下 谁更可能获胜。

题解:

        巴什博弈   在两人都足够聪明的情况下,结局是固定的。

#include <stdio.h>

int n;
int main()
{
    int n;
    while(~scanf("%d", &n))
        if(n%4 == 0)    puts("XX");
        else    puts("DD");
  return 0;
}

D、甜甜圈

题目大意:

        给定首尾相接的n个数,有 t 个问题,每个问题有两个参数 i , j;问 该数组中[i, j]的和是多少。

题解:

        首先我们先建一个数组ans,令ans[i]为原始a数组中前 i 个数的和,那么对于每个问题的参数。
        可得:ans[j] = a[1] + a[2] + ...... + a[i] + a[i + 1] + ...... + a[j – 1] + a[j];
        但是我们只需要知道 a[i] + a[i + 1] + a[i + 2] + ...... + a[j – 1] + a[j];
        同理我们可知:ans[i – 1] = a[1] + a[2] + a[3] + ...... + a[i - 2] + a[i – 1];

        所以我们可以得出 对于原始a数组中[i, j] 的和为ans[ j ] – ans[ i – 1];

但是这个公式只对于i < j的时候,那当i > j的时候呢?

        题目所述,该数组是首尾相接的,则当i > j 时,我们的答案应该是
                a[i] + a[i + 1] + a[i + 2] + ...... + a[n] + a[1] + a[2] + ...... + a[j - 1] + a[j];
        由我们对ans的定义可知道:ans[n] = a[1] + a[2] + a[3] + a[4] + ...... + a[n – 1] + a[n];

        对于ans[n] 我们只需要减去多加的部分可以了,因为j < i 所以我们可知多加的部分为:
                 a[j + 1] + a[j + 2] + a[j + 3] + ...... + a[i – 2] + a[i - 1] = ans [i – 1] – ans[j];

        则当 i > j 时,其结果为:ans[n] - ans[i – 1] + ans[j];

        我们只需要判断 i 和 j 的大小情况输出相应的公式即可

(这题可以暴力 但不建议,因为这里只是数据弱,对于强一点的数据很容易超时)

#include <stdio.h>

int n, m;
int a[10010];
int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d", a + i);
        a[i] += a[i - 1];
    }
    scanf("%d", &m);
    
    while (m --)
    {
        int x, y;   scanf("%d%d", &x, &y);
        if(x <= y)
            printf("%d\n", a[y] - a[x-1]);
        else    printf("%d\n", a[n] - a[x-1] + a[y]);
    }
    return 0;
}

     

F、特别的数组

题目大意:

        给定一个大小为n的数组,你可以在数组最后添加一个非负数,使该数组的平均值等于1,问 最少添加几个数才能使其数组平均值变为1。

题解:

        首先令sum为给定数组的和,则由题可分类为:sum == n、sum > n、sum < n;

        很显然当sum == n时,sum / n == 1;所以这种情况只需要输出0即可。

        当sum > n时,sum / n必然大于1,要是sum / n变小,我们需要将被除数变小,除数变大;但是由题可知,我们所添加的数只能是非负数,所以我们无法将sum变小,只能在sum保持不变的情况下将n变大,则我们只需要在数组最后添加sum - n个0即可,所以答案为sum – n。

        当sum < n就更简单了,我们只需要令sum == n,所以我们在数组后面添加一个数 n – sum,则操作数为 1,答案为 1。

#include <stdio.h>
int n, a[1010], ans;

int main()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d", a + i);
        ans += a[i];
    }
    if(ans == n)    ans = 0;
    else if(ans > n)    ans = ans - n;
    else    ans = 1;
    
    printf("%d\n", ans);
    
    return 0;
}

H、对角线

题目大意:

        对于一个有n个顶点的凸多边形,求其对角线交点的个数。

题解

        首先分析一下交点个数怎么求。一个四边形,交点只有一个,也就是,四个顶点,确定一个交点,所以边少于4的图形都没有对角线,更别谈交点了。那么n边形(n>=4),也就是从n个顶点里面选取四个,且没有顺序,所以顶点个数就是4Cn,既得到公式
                                 ans = n * (n-1) * (n-2) * (n-3)/(4 * 3 * 2 * 1)

#include <stdio.h>
int main()
{
    long long n;
    while(~scanf("%lld",&n))
        printf("%lld\n", n * (n - 1) / 2 * (n - 2) / 3 * (n - 3) / 4);
    return 0;
}

I、进制转换

题目大意:

        将一个八进制数字转换成十六进制,不输出前导0。

题解:

        单纯的模拟题,直接模拟一遍就可以了,只是要注意时间复杂度不要超时
        (但是数据可能没那么强,一般的模拟也不会超)

#include <stdio.h>
#include <string.h>
#define N 10010
#define M 30010

int a[4] = {1, 2, 4, 8};
char st[10][5] = {"000", "001", "010", "011", "100", "101", "110", "111"};
    // 代码预处理

int main()
{
    int t = 1;  scanf("%d", &t);
    while (t --)
    {
        char ans[N], base_8[N], base_2[M] = {'\0'};     // 对base_2数组清空;
        scanf("%s", base_8);
        
        for(int i = 0; i < strlen(base_8); i ++)        // 遍历base_8数组中每一个字符并依次转换为二进制
        {
            int xx = base_8[i] - '0';
            strcat(base_2, st[xx]);
        }
        
        int idx = -1, pos = 0;
        for(int i = strlen(base_2) - 1, j = 0; ~i; i --)
        {
            if(base_2[i] == '1')    pos += a[j];
                j ++;
            
            if(j == 4 || i == 0)            // 四位二进制转一位十六,集齐就转;或者当二进制不够了也转;
            {
                if(pos < 10)    ans[++ idx] = '0' + pos;
                else    ans[++ idx] = 'A' + pos - 10;
            
                j = pos = 0;
            }
        }               // 二转十六进制
        
        int flag = 1;
        for(int i = idx; ~i; i --)                  // 因为二转十六的时候,是从低位开始转的,但是放在ans数组中变成了高位
            if(ans[i] == '0' && flag) continue;         // 所以需要从后往前输出,高位中的0不输出
            else {
                putchar(ans[i]);
                flag = 0;
            }
        puts("");
    }
    return 0;
}


最后小编想说:

        对于这次比赛没有做出题目的同学,并不代表什么。不过是有一部分同学提前学习过而已,后续还会有更多的比赛;

        我相信会有同学能实现弯道超车,ACM协会是一个技术互助的社团,目的是鼓励大家相互学习。大家可以一起讨论,继续参与后续比赛复盘和新的比赛。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值