文章目录
- 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 秒吃一个薯片,问最早什么时候薯片能被吃完。
题目分析
这道题给定三个人吃薯片的时间间隔 t1
、t2
、t3
,以及薯片总数 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
和三个人吃薯片的时间间隔 t1
、t2
、t3
作为参数。通过 t / t1
、t / t2
、t / 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
。当 left
和 right
相等时,二分查找结束,返回 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
的数组 a
、b
、c
,分别表示每天不同活动的朋友人数,要求从三个数组中选择三天,使得对应活动的朋友人数之和最大,且三天不能重复。
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
,以及三个指针 用于返回最大值、次大值和次次大值的索引。初始化 a
、b
、c
为 -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
,两个参数 n
和 d
,分别表示数列的长度和公差。使用 for
循环从 2
到 n + 1
,对于每个 i
,输出 i * d
,这样就构造出了从 2d
到 (n + 1)d
的数列,满足各项都是合数(除了 d
可能为质数的情况,但题目要求构造的数列满足条件即可,不要求证明每个数都是合数)。