2024级SYUCT-ACM新生第三次训练 题解

目录

  • 0001.数组练习1
  • 0002.田忌赛马
  • 0003.梦中的统计
  • 0004.数字反转
  • 0005.九宫格
  • 0006.有强迫症的小明II
  • 0007.矩阵乘法
  • 0008.东风夜放花千树
  • 0009.统计天数
  • 0010.有强迫症的小明III
  • 0011.不要质数
  • 0012.美妙的主对角线
  • 0013.小明不会数
  • 0014.小帅的幻想
  • 0015.杨辉三角
  • 0016.求组合数
  • 0017.斐波那契
  • 0018.1! * 2! = 2!
  • 0019.快乐数组
  • 0020.树的质量(1)
  • 0021.树的质量(2)
  • 0022.树的质量(3)
  • 0023.你好 泥嚎 nihao
  • 0024.MEX(easy version)
  • 0025.MEX(hard version)
  • 0026.虚假的记忆

0001.数组练习1

没什么好说的,就是正着输入,用数组存一下,然后倒着输出

ACcode

#include
int main(){
   
	int n;
	int a[1010]; //尽量比题里的限制开的略大一点
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &a[i]); //正着输入
	for(int i = n - 1; i >= 0; i--) printf("%d ", a[i]); //倒着输出
	return 0;
}

0002.田忌赛马

田忌采取的策略是:用最差的马对抗达奇最好的马,用次差的马对抗次好的马,… ,最后用最好的马对抗达奇最差的马。

开两个数组,a数组存田忌的马,b数组存达奇的马,然后开一个循环,每次将田忌的马正序输出,将达奇的马逆序输出就好了。

这题题干里面说了,马夫已经把两人的马按照实力排好了顺序,所以直接输入就行,不用排序

ACcode1

#include 
int a[200005], b[200005];

int main(){
   
	int n;
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &a[i]); //田忌的马
	for(int i = 0; i < n; i++) scanf("%d", &b[i]); //达奇的马
	for(int i = 0; i < n; i++){
   
		printf("%d %d\n", a[i], b[n - 1 - i]);
	}
	return 0;
}

当然,你也可以将达奇的马逆序存储,然后他俩都正序输出就好了

ACcode2

#include 
int a[200005], b[200005];

int main(){
   
	int n;
	scanf("%d", &n);
	for(int i = 0; i < n; i++) scanf("%d", &a[i]); //田忌的马
	for(int i = n - 1; i >= 0; i--) scanf("%d", &b[i]); //达奇的马
	for(int i = 0; i < n; i++){
   
		printf("%d %d\n", a[i], b[i]);
	}
	return 0;
}

0003.梦中的统计

就是输入两个数m,n(注意:范围比较大,有可能会爆int),用一个for循环遍历m~n中的每一个数,用while循环把每个i的每一位取出来(这里记得用一个变量替换i,否则会死循环),用一个长度为10cnt数组来存每一个数字出现的次数,cnt[i]就是数字i出现的次数,因为下标是0~9,所以长度开到10刚好,把每个位置初始化成0,每次对while循环取出的余数在数组中对应的位置+1,(cnt[t%10]++),然后for循环从09遍历一遍输出就好了

需要注意:因为while循环的判断条件为t!=0,所以0不会进入while循环,就不会加到答案中,要特判这种情况。

ACcode

#include
int cnt[10]; //计数数组,cnt[i]表示i出现的次数
int main(){
   
	long long m, n;
	scanf("%lld%lld", &m , &n);
	for(long long i = m; i <= n; i++){
    //i遍历m~n的每一个数
		long long t = i; //用t代替i取位,防止死循环
		if(i == 0) cnt[0]++; //特判0的情况
		while(t){
   //while循环取出t(i)的每一位
			cnt[t % 10]++; //将取出来的数字累加到计数数组中
			t /= 10;
		}
	}
	for(int i = 0; i < 10; i++){
   
		printf("%d ", cnt[i]); //遍历数组,输出结果
	}
	return 0;
}

0004.数字反转

这题其实不用数组也可以做,因为C语言的取模和数学中的取模不太一样

在数学中,取模运算的结果总是跟被除数同号。
比如:
5 m o d 3 = 2 5 mod 3 = 2 5mod3=2
− 5 m o d 3 = 1 ( 因为 − 5 = − 2 ∗ 3 + 1 ) -5 mod 3 = 1 (因为 -5 = -2 * 3 + 1) 5mod3=1(因为5=23+1)
5 m o d − 3 = − 1 ( 因为 5 = − 1 ∗ ( − 3 ) − 1 ) 5 mod -3 = -1 (因为 5 = -1 * (-3) - 1) 5mod3=1(因为5=1(3)1)
− 5 m o d − 3 = − 2 ( 因为 − 5 = 1 ∗ ( − 3 ) − 2 ) -5 mod -3 = -2 (因为 -5 = 1 * (-3) - 2) 5mod3=2(因为5=1(3)2)

在C语言中,取模运算符 % 的结果符号与被除数相同:
5 % 3 = 2 5 \% 3 = 2 5%3=2
− 5 % 3 = − 2 -5 \% 3 = -2 5%3=2
5 % − 3 = 2 5 \% -3 = 2 5%3=2
− 5 % − 3 = − 2 -5 \% -3 = -2 5%3=2
我们可以用一个简单的式子来表示这种关系:
a % b = a - (a / b) * b (其中 / 是C语言的整除运算)

由此可见,当n为负数的时候取模10结果就是负数,所以负数也可以通过不断取模翻转过来,一开始定义一个变量t0,每次让t=t*10+n%10就行了,具体的原理在2024级SYUCT-ACM新生第二次训练 题解的数字反转中已经讲过。

ACcode

#include
int main(){
   
	long long n; //n的范围已经超过1e9,要开long long
	scanf("%lld", &n);
	long long t = 0; //t记录翻转后的数
	while(n){
    //while循环取出n的每一位
		t = t * 10 + n % 10; //每次将t*10将t向前移一位,把个位空出来,将n%10放到个位
		n /= 10;
	}
	printf("%lld", t);  //输出结果
	return 0;
}

0005.九宫格

就是用一个二维数组存数,然后判断8个和是不是相等

这题需要注意一点:C语言里面不能写连续的判断,比如if(a>b>c) if(a==b==c),你只能一次写一个判断,用&&把他们连起来,就像if(a>b && b>c) if(a==b && b==c)
这是因为C语言的语句是从前往后执行的,大家都知道真为1,假为0,如果你写4>3>2,它会先判断4>3,返回1,然后判断1>2,返回0,判断就错了

ACcode

#include 
int main(){
   
	int a[3][3]; // 使用a作为3x3二维数组的名称
    int sum1, sum2, sum3, sum4, sum5, sum6, sum7, sum8;
    // 读取九宫格的数字
    for 

你可能感兴趣的:(c语言,算法)