浙邮院新生选拔赛解题报告

浙邮院新生选拔赛(题解报告)-by angel_demon

A:圆的直径、周长和面积

sol: 题目说输入只有一行,没说多组测试数据,所以连循环输入都不用。用double和float都能AC,但是一般碰到小数的题目建议使用double,因为double更加精确。

#include <cstdio>
#include <cmath>
using namespace std;
const double PI = 3.1415926;
int main() {
	double r, d, p, s;
	scanf("%lf", &r);
	d = 2 * r;
	p = d * PI;
	s = r * r * PI;
	printf("%.2lf %.2lf %.2lf\n", d, p, s);
	return 0;
}



B:07的游泳时间

sol: 先直接拿第二个时间的小时和分减第一个时间的小时和分,得到的小时一定不小于0,得到的分可能小于0,那么我们只要处理一些负的分就好了,如果分为负数,分加上60,小时减1。

#include <cstdio>
using namespace std;
int main() {
	int a, b, c, d;
	while (~scanf("%d%d%d%d", &a, &b, &c, &d)) {
		int e = c - a;
		int f = d - b;
		if (f < 0) {
			f += 60;
			e -= 1;
		}
		printf("%d %d\n", e, f);
	}
	return 0;
}

ps: ~scanf("%d%d%d%d", &a, &b, &c, &d) 和 scanf("%d%d%d%d", &a, &b, &c, &d) != EOF 作用一样



C:小明A+B

sol: A + B 很好算,这题只要将结果保留最后两位就好了, 那么我们可以通过对100取余得到最后两位。

#include <cstdio>
using namespace std;
int main() {
	int t, a, b;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &a, &b); 
		a %= 100;
		b %= 100; 
		printf("%d\n", (a + b) % 100); // 取余的优先级和乘除一样高 
	}
	return 0;
}

ps: a %= 100; 和 b %= 100;这两句不加也可以通过这题,但是按照题目要求是必须加上的,因为题目中说(A和B均在int型可表示的范围内). 大家都知道int范围是有上限的,太大的数字是装不了的。A、B都在int型可表示范围,那么如果A和B都是int的边界,A + B就会超出int可表示范围。比如输入两个2147483647。同学们可以测一下自己的代码能不能得到94这个结果。当然也可以采用长整型long long来解决这个问题。



D:幸运数

sol: 这一题就是一个数位分离,可以用循环把年月日的所以位数分离出来,分出一个消一个具体的还是看代码理解吧

#include <cstdio>
using namespace std;
int main() {
	int a, b, c; // int sum = 0;
	while (~scanf("%d%d%d", &a, &b, &c)) {
		int sum = 0;
		while (a != 0) {
			sum += a % 10; // 取出a的个位 
			a /= 10;       // 消除a的个位 
		}
		while (b != 0) {
			sum += b % 10; // 取出b的个位 
			b /= 10;       // 消除b的个位 
		}
		while (c != 0) {
			sum += c % 10; // 取出c的个位 
			c /= 10;       // 消除c的个位 
		}
		printf("%d\n", sum % 10);
	}
	return 0;
}

ps: 比较容易出现的错误是像我上面注释的那样把sum = 0写到了外面,要注意我们的这道题目是多组测试数据,如果sum = 0; 写在了while的外面,第一组数据的sum是等于0,但是第二次进入循环sum就会保留第一组数据的结果。所以要写在循环里面,每次进入循环都重新把sum的值设置成0。



E:汉堡包

sol: 输入n个数,同时判断哪些数是不超过100的,再把所有不超过100的数加起来。

#include <cstdio>
using namespace std;
int main() {
	int n, m, sum = 0;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d", &m);
		if (m <= 100) sum += m;
	}
	printf("%d\n", sum);
	return 0;
}



F:谁拿了最多的奖学金

sol: 这题就是题目长了点,if多了点,求出每个同学的奖学金数量,再和之前奖学金最多的同学比较一下就好了

#include <cstdio>
using namespace std;
int main() {
	int n, ans = 0;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		int a, b, c, sum = 0;
		scanf("%d%d%d", &a, &b, &c);
		if (a >= 80 && c >= 1) sum += 8000;
		if (a >= 85 && b >= 80) sum += 4000;
		if (a >= 90) sum += 2000;
		if (sum > ans) ans = sum;
	}
	printf("%d\n", ans);
	return 0;
}


G:最右边的数字

作为压轴题,当然是要带点坑的。很多同学直接求了n的n次方然后对10取余。但是我在上面的C题也提到了,int范围有限。n的最大范围是1000,那么1000的1000次方想一想就知道是个天文数字,远超过int的极限值。有同学考虑到int范围问题然后改用了long long,但是long long的极限范围大概是int范围的平方,也是无法装那么大的一个数了。那么这个问题该怎么解决呢?

sol1: 用同余定理。可以自己去百度里查一下,大概就是说a * b % p我们可以转化成((a % p) * (b % p)) % p。举个例子34 * 101 % 8 -> ((34 % 8) * (101 % 8)) % 8 -> 2 * 5 % 8 ->2。

#include <cstdio>
using namespace std;
int main() {
	int t, n;
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		int ans = 1;
		for (int i = 1; i <= n; i++) {
			ans *= n;
			ans %= 10;
		}
		printf("%d\n", ans);
	}
	return 0;
}

sol2: 找规律。

昨天AK的4位同学里,有同学想到了比较新奇的另一种解法。先来看一下他的代码

#include <cstdio>
#include <iostream>

using namespace std;

int main() {
	int n;
	while (cin >> n) {
		while (n--) {
			int m;
			cin >> m;
			if (m % 10 == 1) {
				cout << 1 << endl;
			} else if (m % 10 == 2) {
				int i[] = {6, 2, 4, 8};
				cout << i[(m % 4)] << endl;
			} else if (m % 10 == 3) {
				int i[] = {1, 3, 9, 7};
				cout << i[(m % 4)] << endl;
			} else if (m % 10 == 4) {
				int i[] = {6, 4};
				cout << i[(m % 2)] << endl;
			} else if (m % 10 == 5) {
				cout << 5 << endl;
			} else if (m % 10 == 6) {
				cout << 6 << endl;
			} else if (m % 10 == 7) {
				int i[] = {1, 7, 9, 3};
				cout << i[(m % 4)] << endl;
			} else if (m % 10 == 8) {
				int i[] = {6, 8, 4, 2};
				cout << i[(m % 4)] << endl;
			} else if (m % 10 == 9) {
				int i[] = {1, 9};
				cout << i[(m % 2)] << endl;
			} else if (m % 10 == 0) {
				cout << 0 << endl;
			}
		}
    }
	return 0;
}

这份代码用到了还没有讲过的关于数组的内容,大概就是说当m的个位是1的时候,m的m次方个位总是1;当m个位是2的时候,m的m次方个位总是在6, 2, 4, 8这几个数里面循环。。。。。。

其实m的m次方的个位总是在0, 1, 4, 7, 6, 5, 6, 3, 6, 9, 0, 1, 6, 3, 6, 5, 6, 7, 4, 9这几个数里循环,下面是我的代码

#include <cstdio>
using namespace std;
int a[] = {0, 1, 4, 7, 6, 5, 6, 3, 6, 9, 0, 1, 6, 3, 6, 5, 6, 7, 4, 9};
int main() {
	int t, n;
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		printf("%d\n", a[n % 20]);
	}
	return 0;
}

因为没有讲过数组,这边还有一份swtich的代码来帮助大家理解

#include <cstdio>
using namespace std;
int main() {
	int t, n;
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		switch (n % 20) {
			case 0 : printf("0\n"); break;
			case 1 : printf("1\n"); break;
			case 2 : printf("4\n"); break;
			case 3 : printf("7\n"); break;
			case 4 : printf("6\n"); break;
			case 5 : printf("5\n"); break;
			case 6 : printf("6\n"); break;
			case 7 : printf("3\n"); break;
			case 8 : printf("6\n"); break;
			case 9 : printf("9\n"); break;
			case 10 : printf("0\n"); break;
			case 11 : printf("1\n"); break;
			case 12 : printf("6\n"); break;
			case 13 : printf("3\n"); break;
			case 14 : printf("6\n"); break;
			case 15 : printf("5\n"); break;
			case 16 : printf("6\n"); break;
			case 17 : printf("7\n"); break;
			case 18 : printf("4\n"); break;
			case 19 : printf("9\n"); break;
		}
	}
	return 0;
}

比较sol1和sol2哪种方法好呢?很多同学可能觉得sol1简单,比较好。但其实sol2这种方法更好,这道题的原题是台州OJ1316题,那么对于那题n的范围是1000000000,用sol1虽然结果正确但是会超时,但是用sol2求n的n次方不用循环n次,计算一次就能得到结果。所以如果对n的范围进行加大,可能只有sol2才能通过题目。


为解题报告打分
暂时不评分

★★
★★★
★★★★
★★★★★
发表您的评论(若贴AC代码或发表禁止言论等违禁行为将被删除并扣除积分)

|返回 |   | 转到页头|
Copyright @ 2008-2024(浙ICP备2022001332号), TZOJ. All Rights Reserved.