2024西游新生赛部分题解

文章目录

  • B 我才是奶龙
    • 题目大意
    • 题目分析
    • 答案
  • D 琪露诺和三角形
    • 题目大意
    • 题目分析
    • 方法一
    • 方法二
  • J 六花和薯片
    • 题目大意
    • 题目分析
  • K 小鸟游的寒假
    • 题目大意
    • 题目分析
  • L 白小藜和合数
    • 题目大意
    • 题目分析

B 我才是奶龙

题目大意

众所周知,奶龙是一只喜欢重量级的黄色 小龙,现在有一只小白龙试图变成奶龙,但是颜色和奶龙不一样(一个白色一个黄色);于是他找到R G B三种颜色,自己调出黄色给自己上色。

为了简化问题,我们用三个字符R、G、B分别表示红色、绿色和蓝色;如果小白龙可以调出黄色输出YES,否则输出NO。输出不包括引号,注意大小写。

注:黄色只能由红色和绿色相加而成,换句话说,挑选的颜色中恰好只有R和G时输出YES;否则输出NO

输入格式

第一行输入一个整数n表示小白龙选择的颜色数量(1 <= n <= 3)。

接下来依次输入n行,每行输出R、G、B 中的其中一个代表小白龙选择的颜色。小白龙可以选择同一个颜色不止一次,详情看第三组样例。

输出格式

小白龙可以调出黄色输出YES,否者输出NO。

样例数据

输入1

3
R
G
B

输出1

NO

输入2

2
G
R

输出2

YES

输入3

3
R
G
R

输出3

YES

样例解释

样例一:输入不仅包含R、G还有B,不符合恰好只有R、G,故输出NO。

样例二:输入只包含R、G,故输出YES。

样例三:输入虽然有三个颜色,R选了两次,但是恰好只有R、G,故输出YES。

题目分析

​ 我们需要判断小白龙挑选的颜色是否构成恰好合成绿色的条件,换句话说就是判断输入的所有字母中是否只包含R和G而不包含B。这道题我们理论上可以使用布尔数组来分别存储并判断是否出现R、G、B的情况,但由于我是若至,我希望拿我仅学到数组的脑子来解开这道题。那么,我们该怎么做呢?

​ 首先,关闭电脑,洗洗睡吧。

​ 其次,我们根据题目要求的输入格式输入一个整数n和一个大小为n的字符型数组。但是如果直接arr[n]的话翻车的可能性极大,所以我们使用动态内存分配:

c 复制代码
    int n;
    scanf("%d", &n);
    char *arr = (char *)malloc((n) * sizeof(char));
    if (arr == NULL) {
        return 1;
    }

​ 注意,如果要输入字符型数组元素,当你使用scanf("%c", &arr[i]);时,如果输入流中存在空白字符(如换行符),它们会被读取并存储在数组中。这可能会导致你的逻辑出错。你可以使用scanf(" %c", &arr[i]);(注意%c前的空格)来忽略任何空白字符:

c 复制代码
for (int i = 0; i < n; i++) {
        scanf(" %c", &arr[i]); 
    }
    arr[n] = '\0'; 

​ 遍历完数组,我们需要判断这个数组的成分。比较简单的一个方法就是,我们定义三个整数并初始化为0,然后我们在遍历整个数组,如果遍历到某一个字母,就给相应的数字赋值1(因为在一遍遍的循环中,只要某个字母对应的整数有一次被赋值为1,那么不管这个字母后面是否出现或出现几次,它所对应的整数都一定保持为1)。

​ 遍历完数组后,我们仅需一个if语句即可判断输入是否所需题目要求。

c 复制代码
    int r = 0, g = 0, b = 0;

    for (int j = 0; j < n; j++) {
        if (arr[j] == 'R') {
            r = 1;
        } else if (arr[j] == 'G') {
            g = 1;
        } else if (arr[j] == 'B') {
            b = 1;
        }
    }

    if (r == 1 && g == 1 && b == 0) {
        printf("YES\n");
    } else {
        printf("NO\n");
    }

答案

c 复制代码
#include <stdio.h>
#include <stdlib.h>

int main() {
    int n;
    scanf("%d", &n);
    // 使用动态内存分配来创建数组
    char *arr = (char *)malloc((n) * sizeof(char));
    if (arr == NULL) {
        // 如果内存分配失败,退出程序
        return 1;
    }

    for (int i = 0; i < n; i++) {
        scanf(" %c", &arr[i]); // 注意%c前的空格,用于忽略空白字符
    }
    arr[n] = '\0'; // 确保字符串以空字符结尾

    int r = 0, g = 0, b = 0;

    for (int j = 0; j < n; j++) {
        if (arr[j] == 'R') {
            r = 1;
        } else if (arr[j] == 'G') {
            g = 1;
        } else if (arr[j] == 'B') {
            b = 1;
        }
    }

    // 检查是否同时出现'R'和'G',并且没有出现'B'
    if (r == 1 && g == 1 && b == 0) {
        printf("YES\n");
    } else {
        printf("NO\n");
    }

    // 释放动态分配的内存
    free(arr);
    return 0;
}

D 琪露诺和三角形

题目大意

给你一个实数 T T T,构造一个周长面积都为 T T T 的三角形。

题目分析

这道题要求构造一个周长和面积都为给定实数 T 的三角形。提供了两种方法来解决该问题,方法一利用椭圆焦点三角形的性质来确定是否有解以及构造三角形;方法二则假设构造等腰三角形,通过二分法求解边长。

方法一

c 复制代码
#include <stdio.h>
#include <math.h>

void calculate(double T)
{
    double a,b,c,y;
    c=T/6;
    a=T/2-c;
    b=sqrt((T*T/4)-T*c);
    y =T/(2*c);

    // 输出三角形顶点坐标,焦点在x轴上,两个焦点坐标为(-c, 0)和(c, 0),第三个顶点坐标为(0, y)
    printf("(%.10lf, 0.0000000000)\n", -c);
    printf("(%.10lf, 0.0000000000)\n", c);
    printf("(0.0000000000, %.10lf)\n", y);
}

int main() {
    double T;
    scanf("%lf", &T);

    if (T>= 12*sqrt(3)) 
    {
        calculate(T);
    } else 
    {
        printf("No\n");
    }

    return 0;
}

首先根据椭圆焦点三角形周长恒定的性质,已知周长 T,计算出半焦距 c = T / 6。然后计算半长轴 a = T / 2 - c。接着通过椭圆的性质 a^2 = b^2 + c^2,计算半短轴 b = sqrt((T * T / 4) - T * c)。最后计算焦点三角形的高 y = T / (2 * c),这里假设焦点在 x 轴上,两个焦点坐标为 (-c, 0)(c, 0),第三个顶点坐标为 (0, y)

从控制台读取输入的实数 T。判断 T 是否大于等于 12 * sqrt(3),如果是,则调用 calculateTriangle 函数计算并输出三角形的顶点坐标;否则输出 No 表示无解。

方法二

c 复制代码
#include <stdio.h>
#include <math.h>

//计算等腰三角形的边长
double calculate(double T,double low,double high) {
    double mid,a,b,S,C;
    while (high-low>1e-10)
     {
        mid = (low+high)/2;
        // 底
        a = 2*sqrt(mid * mid - (T / 4) * (T / 4));
        // 腰
        b = (T - a / 2);
        // 面积
        S = 0.5*a*sqrt(b*b - (a / 2)*(a / 2));
        // 周长
        C = 2*a + b;

        // 根据面积和周长与目标值的比较调整二分区间
        if (S > T || C < T) {
            high = mid;
        } else if (S < T || C > T) {
            low = mid;
        } else {
            return b;
        }
    }
    return -1;
}

int main() {
    double T, b;
    scanf("%lf", &T);

    // 初始化二分查找区间
    
    double low = T / 4, high = T / 2;
    side = calculate(T,low,high);

    if (side!= -1) {
        // 输出等腰三角形的边长
        printf("%.10lf\n", b);
        printf("%.10lf\n", b);
        printf("%.10lf\n", 2 * sqrt(side * side - (T / 4) * (T / 4)));
    } else {
        printf("No\n");
    }

    return 0;
}

计算等腰三角形边长的函数 calculate,函数使用二分法来逼近满足条件的等腰三角形边长。

首先在 while 循环中,不断计算二分区间的中间值 mid。然后计算底边长度 a = 2 * sqrt(mid * mid - (T / 4) * (T / 4)),这里利用了等腰三角形的性质(假设腰长为 mid,根据勾股定理计算底边)。接着计算腰长 b = (T - base) / 2。再计算面积 S = 0.5 * a * sqrt(b * b - (a/ 2) * (a / 2)) 和周长 C = 2 * b + a。根据面积和周长与目标值 T 的比较结果来调整二分区间,如果 S> T 或者 C < T,说明当前边长过大,将 high 更新为 mid;如果 S < T 或者 C > T,说明当前边长过小,将 low 更新为 mid;如果面积和周长都等于 T,则返回当前边长 b

J 六花和薯片

题目大意

三个人分别每 t 1 、 t 2 、 t 3 t_1、t_2、t_3 t1、t2、t3 秒吃一个薯片,问最早什么时候薯片能被吃完。

题目分析

这道题给定三个人吃薯片的时间间隔 t1t2t3,以及薯片总数 n,要求最早什么时候薯片能被吃完。肯定依旧是通过二分查找来找到满足不等式 ⌊ t / t 1 ⌋ + ⌊ t / t 2 ⌋ + ⌊ t / t 3 ⌋ ≥ n ⌊t/t1⌋ + ⌊t/t2⌋ + ⌊t/t3⌋ ≥ n ⌊t/t1⌋+⌊t/t2⌋+⌊t/t3⌋≥n的最小 t 值。

c 复制代码
#include <stdio.h>

// 计算在时间t内三人吃的薯片总数
int total(int t, int t1, int t2, int t3)
 {
    return (t / t1) + (t / t2) + (t / t3);
}

// 使用二分查找找到最早吃完薯片的时间
int time(int t1, int t2, int t3, int n) {
    int left = 1;
    int right = n * (t1 < t2? t1 : t2) < t3? n * (t1 < t2? t1 : t2) : t3;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (total(mid, t1, t2, t3) >= n) {
            right = mid;
        } else {
            left = mid + 1;
        }
    }
    return left;
}

int main() {
    int t1, t2, t3, n;
    scanf("%d %d %d %d", &t1, &t2, &t3, &n);
    int a = time(t1, t2, t3, n);
    printf("%d\n", a);
    return 0;
}

我首先计算在时间 t 内三人吃的薯片总数的函数,这里调用了 total,然后时间 t 和三个人吃薯片的时间间隔 t1t2t3 作为参数。通过 t / t1t / t2t / t3 分别计算在时间 t 内每个人吃的薯片数量(这里是向下取整的结果,因为在C语言中整数除法会自动向下取整 ),然后将三人吃的薯片数量相加并返回。使用二分查找找到最早吃完薯片时间的函数 time

依然按照套路,初始化二分查找的左边界 left 为1,表示最早可能吃完的时间是1秒。右边界 right 初始化为 n * (t1 < t2? t1 : t2) < t3? n * (t1 < t2? t1 : t2) : t3,这是一个估计的上限,取三人中最小时间间隔的 n 倍和 t3 中的较小值,这样可以保证在这个范围内一定能找到答案(如果时间超过这个上限,即使是吃的最快的人单独吃 n 个薯片也足够了)。

计算中间时间,然后调用 total 函数计算在中间时间 mid 内三人吃的薯片总数,并与 n 进行比较。如果吃的薯片总数大于等于 n,说明可能在更早的时间就吃完了,将右边界 right 更新为 mid;否则,说明时间不够,需要增加时间,将左边界 left 更新为 mid + 1。当 leftright 相等时,二分查找结束,返回 left 作为最早吃完薯片的时间。最后在主函数里面输出调用就行。

K 小鸟游的寒假

题目大意

给定三个长度为 n n n 的数组 a , b , c a, b, c a,b,c,分别表示在第 i i i 天和六花一起吃饭、看电影、玩桌游的朋友人数。每一天只能选择一个活动。

请从这三个数组中选择三天 x , y , z x, y, z x,y,z,使得 a x + b y + c z a_x + b_y + c_z ax+by+cz 最大。

题目分析

这道题给定三个长度为 n 的数组 abc,分别表示每天不同活动的朋友人数,要求从三个数组中选择三天,使得对应活动的朋友人数之和最大,且三天不能重复。

c 复制代码
#include <stdio.h>

// 找到数组中的最大值、次大值和第三大值的索引
void find(int arr[], int n, int *A, int *B, int *C) {
    int a = -1, b = -1, c = -1;
    for (int i = 0; i < n; i++) 
    {
    
        if (arr[i] > a)
         {
            c = b;
            b = a;
            a = arr[i];
            *C = *B;
            *B = *A;
            *A = i;
            
        } 
        
        else if (arr[i] >b) {
            c = b;
            b = arr[i];
            *C = *B;
            *B = i;
        } 
        else if (arr[i] > c) {
            c = arr[i];
            *C = i;
        }
    }
}

找到数组中的最大值、次大值和次次大值索引的函数 find。数组 arr 和数组长度 n,以及三个指针 用于返回最大值、次大值和次次大值的索引。初始化 abc 为 -1,表示初始没有找到最大值。遍历数组,对于每个元素 arr[i]:如果 arr[i] 大于当前最大值 a,则更新最大值、次大值和次次大值及其索引。将原来的最大值 a 变为次大值 b,原来的次大值 b 变为次次大值 c,并更新相应的索引。如果 arr[i] 大于当前次大值 b,则更新次大值和次次大值及其索引。如果 arr[i] 大于当前次次大值 c,则更新次次大值及其索引。

L 白小藜和合数

题目大意

给你 n n n 和 d d d,构造一个长度为 n n n、公差为 d d d,且各项都是合数的等差数列。

题目分析

这道题要求构造一个长度为 n、公差为 d,且各项都是合数的等差数列。根据题解思路,利用 d 的倍数来构造这个数列,从 2d 开始,到 (n + 1)d 结束,这样可以保证数列中的数除了 d 本身(当 d 为质数时),其他都是合数。

c 复制代码
#include <stdio.h>

void con(int n, int d) {
    for (int i = 2; i <= n + 1; i++) {
        printf("%d ", i * d);
    }
}

int main() {
    int n, d;
    scanf("%d %d", &n, &d);
    con(n, d);
    return 0;
}

构造并输出全是合数的等差数列的函数 con,两个参数 nd,分别表示数列的长度和公差。使用 for 循环从 2n + 1,对于每个 i,输出 i * d,这样就构造出了从 2d(n + 1)d 的数列,满足各项都是合数(除了 d 可能为质数的情况,但题目要求构造的数列满足条件即可,不要求证明每个数都是合数)。

相关推荐
程序趣谈27 分钟前
算法随笔_12:最短无序子数组
算法
JaneZJW1 小时前
Linux C编程:文件IO(概念、打开、读、写、关闭)
linux·c语言·stm32·单片机·嵌入式
米饭「」1 小时前
数据结构-栈和队列
java·开发语言·数据结构
WXG10111 小时前
【matlab】matlab知识点及HTTP、TCP通信
算法
岸榕.2 小时前
树的连边II
算法·深度优先·图论
ExRoc2 小时前
蓝桥杯真题 - 异或和之差 - 题解
c++·算法·蓝桥杯
Python_enjoy2 小时前
洛谷题解 - P1003 [NOIP2011 提高组] 铺地毯
数据结构·c++·算法
理智的灰太狼2 小时前
求两个矩阵的乘积
线性代数·算法·矩阵
明月醉窗台2 小时前
C++ 之多线程相关总结
开发语言·c++·算法
多多*2 小时前
Java锁 从乐观锁和悲观锁开始讲 面试复盘
java·开发语言·前端·python·算法·面试·职场和发展