SDNU-ACM 202210.23Weekly Practice-个人赛

目录

前言 

Problem A

思路

AC代码

 Problem B

 思路

AC代码

Problem E

AC代码 

Problem G

思路 

AC代码

Problem H 

回顾

AC代码

Problem I 

思路

AC代码

Problem K 

思路

AC代码

Problem L 

 思路

AC代码

Problem F (未AC)

思路

补题代码

 Problem J(未AC)

思路

补题代码

Problem C(未AC)

思路

补题代码

总结


前言 

这次还行捏,虽然最后十分钟被挤出前五了,但是至少没有上次那样差一丢丢的题了。有一些题用了笨方法,虽然能过就不错,但还是希望可以优化自己的想法捏。

依然,欢迎纠错,欢迎优化。

Problem A

A - A Recursive Function

SDNU-ACM 202210.23Weekly Practice-个人赛_第1张图片 

思路

求阶乘,递归也行。

AC代码

#include 
using namespace std;

int f(int x) {
	if (x == 0)
		return 1;
	else {
		return x * f(x - 1);
	}
}

int main() {
	int n;
	cin >> n;
	cout << f(n) << '\n';
	return 0;
}

 Probl
em B

 B - Broken Rounding

SDNU-ACM 202210.23Weekly Practice-个人赛_第2张图片 

 思路

关注样例可知,题目要求是一位一位四舍五入而非直接在10^k位四舍五入,所以用/和%分离出每一位做四舍五入。

AC代码

#include 
using namespace std;
int main() {
	long long int num, n;
	cin >> num >> n;
	long long int x = 1;
	long long int end;
	for (int i = 1; i <= n; ++i) {
		if (num % 10 >= 5) {    //五入
			num /= 10;
			num += 1;
			x *= 10;
		} else {                //四舍
			num /= 10;
			x *= 10;
		}
	}
	end = num * x;    //在循环中记录了除的次数,最后直接乘即可
	cout << end << '\n';
	return 0;
}

Problem E

 E - Integer Sum

SDNU-ACM 202210.23Weekly Practice-个人赛_第3张图片 

水题。

AC代码

#include 
using namespace std;
int main() {
	int n, sum = 0;
	cin >> n;
	while (n--) {
		int num;
		cin >> num;
		sum += num;
	}
	cout << sum << '\n';
	return 0;
}

 

Problem G

 G - Max Even

SDNU-ACM 202210.23Weekly Practice-个人赛_第4张图片 

思路 

偶数=奇+奇=偶+偶。所以 我们把奇数和偶数放到两个数组里,后面我是笨拙地分类讨论了,看师哥的解法可以先让ans = -1,再来两次对数组容量的判断,取出得数最大值,两次都没进if,ans即-1,复杂度差不多,写起来快一点。

AC代码

#include 
using namespace std;

bool cmp(int a, int b) {
	return a > b;
}

int main() {
	int n;
	cin >> n;
	vectorji;
	vectorou;
	int t;
	while (n--) {
		cin >> t;
		if (t % 2 == 0)
			ou.push_back(t);
		else
			ji.push_back(t);
	}    //在输入时直接放到对应数组里
	sort(ji.begin(), ji.end(), cmp);
	sort(ou.begin(), ou.end(), cmp);
        //sort里调用cmp会更慢一点(但是方便)
	int num;
	if (ji.size() <= 1 && ou.size() <= 1) {
		num = -1;
	} else if (ji.size() <= 1 && ou.size() > 1) {
		num = ou[0] + ou[1];
	} else if (ji.size() > 1 && ou.size() <= 1) {
		num = ji[0] + ji[1];
	} else {
		num = max(ji[0] + ji[1], ou[0] + ou[1]);
	}
        //如果直接sort顺序排,这步可以写成:ji.back()    vector中数组最后一位的值
        //   (int)ji.size()-2    数组长度-2即倒数第二位的地址,强制类型转换为其值
   	cout << num << '\n';
	return 0;
}

Problem H 

 H - 484558

SDNU-ACM 202210.23Weekly Practice-个人赛_第5张图片 

回顾

我真的会谢!之前做那个十转十六进制的题用了scanf/printf的%x,d然后wa了,后来同学给我讲了半天,这方法的问题在于:如果数据过大,计算机中以二进制形式存储十进制数据的符号位会变成十六进制数据的真实数字位,此时数据会错误。(有点绕,多看几遍就懂了)

但是这个题完全涉及不到符号位!我不看数据我是大笨蛋!唯一一发wa也献给了这题因为多判断了一层0。

感谢我那讲不明白课的C语言老师在上节课提到了格式化字符,我当时查了查他是一个可以补位补0的神奇操作,也是没想到能这么快用上。

AC代码

#include 
using namespace std;

char number(int x) {
	if (x < 16 && x > 9) {
		return x + 'A' - 10;
	} else if (x < 10 && x >= 0) {
		return x + '0';
	} else
		return -1;
}

int main() {
	char sixteen[2] = {'0'};
	long long int x;
	cin >> x;
	for (int i = 1; i >= 0; --i) {
		int t = x % 16;
		char c = number(t);
		sixteen[i] = c;
		x /= 16;
	}
	for (int j = 0; j <= 1; ++j) {
		printf("%c", sixteen[j]);
	}
	cout << endl;
	return 0;
}

Problem I 

 I - Maintain Multiple Sequences

 SDNU-ACM 202210.23Weekly Practice-个人赛_第6张图片

 

思路

二维数组。直接开数组必爆啊,看到师哥是开了定列数动态维护行数的vector,我是直接vector了两层,这样会有一个输入的问题,不能直接按数组的方式输入数据,因为在没加行之前,数组是空的,数是输不进去的,我又开了一个vector记录每一行的数然后把这一行导入二维数组。

AC代码

#include 
using namespace std;

int main() {
	vector>arr;
	int n, q;
	scanf("%d %d", &n, &q);

	for (int i = 1; i <= n; ++i) {
		int hang;
		scanf("%d", &hang);
		vectorv;
        //把数组开到括号里就不用管清数据的问题了
		for (int j = 1; j <= hang; ++j) {
			int t;
			scanf("%d", &t);
			v.push_back(t);
		}
		arr.push_back(v);
	}
	while (q--) {
		int a, b;
		cin >> a >> b;
		cout << arr[a - 1][b - 1] << '\n';
	}
	return 0;
}

 

Problem K 

 K - 1-2-4 Test

SDNU-ACM 202210.23Weekly Practice-个人赛_第7张图片 

思路

位运算的奇淫巧计。师哥写的位运算真的好简单,看完我只能说妙啊。我愿称我的答案为愚蠢的穷举。

位运算:题目给的数很妙,每一题代表二进制的一位,要知道计算机存储数据都是二进制的,所以按位或一下就得到了Snuke的分数(二进制),输出来就是答案了。

分类讨论:(幸好他只有三个题)bool三个,列举出所有可能的得分,前两人有一个过了题即true,最后让为true的题加分就行了。

这里是只会看不会用位运算的小姐姐一枚啊~ 

AC代码

#include 
using namespace std;

int main() {
	int a, b, c = 0;
	cin >> a >> b;
	bool f1 = 0, f2 = 0, f4 = 0;
	if (a == 1 || b == 1)
		f1 = 1;
	if (a == 2 || b == 2)
		f2 = 1;
	if (a == 3 || b == 3) {
		f1 = 1;
		f2 = 1;
	}
	if (a == 4 || b == 4) {
		f4 = 1;
	}
	if (a == 5 || b == 5) {
		f1 = 1;
		f4 = 1;
	}
	if (a == 6 || b == 6) {
		f2 = 1;
		f4 = 1;
	}
	if (a == 7 || b == 7) {
		f1 = 1;
		f2 = 1;
		f4 = 1;
	}
	if (f1 == 1)
		c += 1;
	if (f2 == 1)
		c += 2;
	if (f4 == 1)
		c += 4;
	cout << c << '\n';
	return 0;
}

Problem L 

 L - Hammer

SDNU-ACM 202210.23Weekly Practice-个人赛_第8张图片 

 思路

小学数学捏,分类讨论。

感觉画一个数轴会比较好理解,如果墙和目标是两个方向路程即目标;else,如果墙比目标离0远,同上;else,如果锤子和墙是两个方向,路程即2*锤子+目标;else,如果锤子比墙离0近,路程即目标;else,取不到。

取绝对值就可以不用讨论正负辽。

AC代码

#include 
using namespace std;
int main() {
	int aim, wall, ha;//ha是hammer
	cin >> aim >> wall >> ha;
	int far;
	if (aim * wall <= 0) {
		far = abs(aim);
	} else {
		if (abs(wall) - abs(aim) >= 0) {
			far = abs(aim);
		} else {
			if (abs(wall) - abs(ha) >= 0) {
				far = abs(ha) + abs(wall - ha) + abs(aim - wall);
			} else {
				far = -1;
			}
		}
	}
	cout << far << '\n';
	return 0;
}

Problem F (未AC)

 F - Everyone is Friends

SDNU-ACM 202210.23Weekly Practice-个人赛_第9张图片 

思路

暴力模拟即可,开个二维bool数组,疯狂循环,因为数据很小所以完全不会t。

另开一个数组记录每次参会的人,二层循环把这些人的[ i , j ]、[ j , i ]格全变为true,最后再遍历数组,遇false则no,不然就yes。

补题代码

#include 
using namespace std;

int n, m;
bool arr[105][105];

int main() {
	cin >> n >> m;
	for (int i = 1; i <= m; ++i) {
		int k;
		cin >> k;
		vectorper;
		for (int j = 1; j <= k; ++j) {
			int t;
			cin >> t;
			per.push_back(t);
		}
		for (int j = 0; j < per.size(); ++j) {
			for (int p = 0; p < per.size(); ++p) {
				arr[per[j]][per[p]] = 1;
				arr[per[p]][per[j]] = 1;
			}
		}
	}
	bool ans = 1;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= i; ++j) {
			if (!arr[i][j]) {
				ans = 0;
                cout << "No" << '\n';
                break;
			}
		}
	}
	if (ans==1)
		cout << "Yes" << '\n';
	return 0;
}

 Problem J(未AC)

 J - Manga

SDNU-ACM 202210.23Weekly Practice-个人赛_第10张图片 

思路

看了师哥的博客才会捏。

bool一个数组,在输入的时候让所有(比n小的)出现过的数为1。然后定义一个num=n,从1到n遍历:如果i没出现过,那就需要用两个数换i;出现过只需要把i减掉就可以。当num<0的时候提前结束循环,本轮ans也不能加上,因为没换成。

补题代码

#include 
using namespace std;
int main() {
	int n, num;
	cin >> n;
	num = n;
	bool arr[300005] = {0};
	for (int i = 0; i < n; ++i) {
		int t;
		cin >> t;
		if (t <= n)
			arr[t] = 1;
	}
	int ans = 0;
	for (int i = 1; i <= n; ++i) {
		if (arr[i] == 0) {
			num -= 2;
			arr[i] = 1;        //需要换书
		} else {
			num -= 1;          //不需要换
		}
		if (num < 0)
			break;
		ans = i;
	}
	cout << ans << '\n';
	return 0;
}

Problem C(未AC)

 C - (K+1)-th Largest Number

SDNU-ACM 202210.23Weekly Practice-个人赛_第11张图片 

思路

 先讲一下题目要求:输入n个数,对于每一次输出,输出n个数里有(本次-1)个数(不重复)比该数大的数的存在次数。例如,第一次输出,我要寻找一个k,使得n个数中存在0(1-1)个数比k大,输出k出现的次数。

对此我的评价是晦涩难懂,当时确实没看懂。

下面做题:由于这个不重复还计次的原则,我们想到用map,从输入的时候就把输入的数字当key值计入map里,输入完成后,其实已经完成找k并计次的操作了,map里元素按key值顺序排列,那么map中倒数第一组的key为最大数,value为该数出现的次数,以此类推,下面我们只需要将map.value倒序输出后补0即可。

注意倒序输出的迭代器要用逆向迭代器!补0可以读一个map.size(),我这里是定义了一个计数器,如果计数器

我!和!map!杠!了!一!晚!上!

补题代码

#include 
using namespace std;
int main() {
	int n;
	cin >> n;
	mapmp;
	for (int i = 0; i < n; ++i) {
		int t;
		cin >> t;
		mp[t]++;
	}    //输入时计入map
	int cnt = 1;
	map::reverse_iterator i;    //逆向迭代器!不然会报错
	for (i = mp.rbegin(); i != mp.rend() ; ++i) {
		cout << (*i).second << '\n';
		cnt++;    //为下面补0定义了一个计数器
	}
	for (cnt; cnt <= n; ++cnt) {
		cout << "0" << '\n';
	}
	return 0;
}

总结

除了两个防ak的剩下都补出来辣!

目前还是存在很多问题,首先就是细节还是不够注意,空格换行边界long long,尤其要注意。然后是复杂度计算,也不是不会算,但还是总爱凭感觉,F题为例,当时觉得循环几次肯定t所以明明想到暴力循环但是完全没有去尝试,这样凭感觉做题不可取捏,是要算算的。还有stl和逆元吧,理解和会用还差得远,很多东西还是要上手写才能发现问题,到现在为止stl的几大容器基本操作都用过了,比刚开始学清楚不少,但还是不熟练,慢慢学吧。

希望月赛能打的好一点呀!

你可能感兴趣的:(sdnu,c++,算法)