东信杯题解详细版本附带代码(还有日常琐碎bb)

日常bb

哎呀总算写完了除了图和树的题。感觉当初新生组还是蛮幸福的,至少除了最后一题的动态规划难了点以外都还是可以做做的。
动态规划如果读懂题意了可以强行数学化,之后再说。
总用时可能要超了点,四个小时有点够呛,毕竟确实强度还是有的,但是如果压轴题不是动态规划我可能就搞不定了。
(主要最后我已经不记得新生组和正式组哪些题了)

题一:区块链(披着创外壳的签到题)

看到这题就直接拉到题面最低端,这题完全是比速度,看谁最先看完题目进行模拟。
模拟规则可能有同学不懂,其实很简单的,去读字符串,如果是字符串输入的读写是会有一个字符串结尾‘\0’然后判定是否这个是\0,不是则打印空格,如果是就打印冒号结束循环。
当然这题最好是存在二维数组方便查找输出结果。给你们代码自查哪里出bug。(本题理论耗时4分钟)
(实际耗时十五分钟,字符串瞎读的我是废物)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
	int n;
	char a[1000][1000];
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
	{
		scanf("%s", &a[i]);
		//这个地方直接读入整串,并且以'\0'结尾
	}
	int m;
	scanf("%d", &m);
	for (int i = 1; i <= m; i++)
	{
		int chs;
		scanf("%d", &chs);
		int j = 0;
		int count = 0;
		while (a[chs][j] != '\0')//判定是否结尾了
		{
			j++;
			count++;
		}
		printf("\"");
		//大家可能有点陌生的转义字符打印类比回车
		for (int j = 0; j < count; j++)
		{
			if (j == count - 1)
			{
				printf("%c", a[chs][j]);
			}
			else
			{
				printf("%c ", a[chs][j]);
			}//细看这里,多打印的空格在这

		}
		printf("\"\n");//打印换行
	}
//缺少一个完美的收官,靠你了
}

题二:人工智能 (看的懂做不出的模拟题)ps:中等难度仅仅对于有模拟经验的选手

第二题同样也是模拟题,只不过这次模拟的是数学乘法。我们分为两部分分析。
第一部分是输入存表如何理解?
通过观察我们可以发现,无论是三张表哪张表,用的都是一套表,只不过输出的区域改变了。
那么只需要把数据存入一张表里就好了,这里的表指的是二维数组。我们可以通过样例发现最大的那张表其实就是full模式下的存储数据,根据gif也可以观测到,我们需要做的事情也就是将表里的一个点作为矩阵1和矩阵2的卷积结果,每次进行一次所谓的卷积运算,就会有一个点被记录下结果。这里大家会开始觉得有点害怕了,其实没必要。我们来一次惊险刺激的复杂度分析,k是3 5 7,n是小于100的数,也就是说,理论上循环四次还没有达到数据爆炸的程度。既然可行,那就努力去做呗。下面是循环打表的代码,大家自查。
第二部分是如何输出三张规格不同的表?
接下来才是真正的重头戏,根据我对这种题目的了解,越是仔细的选手越是快速,越是依赖算法的人反而难以完成打表。口语表达来说已经很清晰了,就是打印出我们脑海中存入的表,但是请注意,每次的卷积,n和k都是不同的,所以真正打出的是一个由n和k决定的动态大小的表。我的做法一般会进行存储优化,将这个表的位置修改为一个大众心仪的位置,然后通过后期的计算去推理得到这个表的参数表。说的很复杂,其实就是列一个2元一次方程的事情,自己造一个k=5的数据去计算表的大小。(总耗时一个半小时,主要卡在了模拟数据推算这个表的输出上了)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<stdbool.h>
int x[2020][2020],y[10][10],z[2020][2020];
long long sum=0;
int main()
{//这里有许多同学可能还没接触,这个是一种初始化数组的方式估计等效于{0},具体我也不懂,我做题喜欢用这个
	memset(x, 0, sizeof(x));
	memset(y, 0, sizeof(y));
	memset(z, 0, sizeof(z));
	int n, m;
	scanf("%d %d", &n, &m);
		for (int i = m;i <= n+m-1;i++) {
		for (int j = m;j <= n+m-1;j++) {
			scanf("%d", &x[i][j])//存表1	
		}
	}
		
	for (int i = 0;i < m;i++) {
		for(int j = 0;j < m;j++){
			scanf("%d", &y[i][j]);//存表2
		}
	}
	int w = (m + 1) / 2;//个人习惯,有利于后面的制表
	for (int i = w;i <= n+m+w;i++) {
		for (int j = w;j <= n+m+w;j++) {
			for (int k = 0;k < m;k++) {
				for (int r = 0;r < m;r++) {
					z[i][j] += x[i+k-w+1][j+r-w+1] * y[k][r];
				}
			}
		}
	}
	//这个四重循环就是我们要做的卷积了,大家可以心里跟着这个过程卷亿卷
	for (int i = 3*w-2;i <=3*w-2+(n-m) ;i++) {
		for (int j = m+w-1;j <= 3 * w - 2 + (n - m);j++) {
			printf("%d ", z[i][j]);
		}//制表1号,难点就在于计算出一般情况下的表怎么打印
		printf("\n");
	}
	for (int i = w;i <= w+n + m-2;i++) {
		for (int j = w;j <=w+ n +m-2;j++) {
			printf("%d ", z[i][j]);
		}//制表二号
		printf("\n");
	}
	for (int i = 2*w-1;i <= 2*w+n-2;i++) {
		for (int j = 2*w-1;j <= 2*w+n-2;j++) {
			printf("%d ", z[i][j]);
		}//制表三号
		printf("\n");
	}
	return 0;//完美收官
}

``//随便说点什么,这题确实很难,不用怀疑,不过做多了就擅长了,这个题目考的不是思维或者算法,考的是细心。

第三题:大数据(字符串正序与倒序)

题意:给你两个字符串,如果这两个字符串刚好是相反的,就qaq否则tat
签到题2,只要你手速够快,理论可以第二分钟a出来,毕竟确实没东西的。
(耗时三分钟,花时间确认上了)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
	int n;
	scanf("%d", &n);
	while (n--) {
		int flag = 1;
		char a[100000];
		char b[100000];
		scanf("%s", &a);
		scanf("%s", &b);
		long long x = strlen(a)-1;
		//减一细节,你存了一个'\0'进去,和之前说的那样,所以要剪掉
		long long r = strlen(b)-1;
		if (x != r) {
			printf("TAT\n");
			continue;
		}//这个在考试中并没有发生效果,原因是出题者也主要是考虑新生实力(可能)
		else;
		for (int i = 0;i < x;i++) {
		//判定呗
			if (a[i] == b[x - i ]) continue;
			else {
				printf("TAT\n");
				flag = 0;
				break;
			}
		}
		if(flag)
		printf("QAQ\n");
	}
return 0;//完美的收官
}

第四题:云计算(排序题)

题目看起来很复杂,甚至会往动态规划方面靠的意思,但是认真看完他给的价值计算公式就会发现,其实是一道数学题。
我们对于给定abc三个数,得到一个一元一次函数,以i为自变量,剩下都是a,b,c,n这些已知量,那么我们就可以很轻易的写出除了i以外的所有数据的和,并将每一个给定abc所得到的和相加,因为都是常数,就无所谓考虑最大最小,真正需要考虑的大小在i上。
现在,我们能做的事情是获得一组k(也就是i的系数),用k去乘以i,获得总和。听起来好像要排列组合把所有情况都统计一遍。但大可不必,你完全可以思考特殊情况。怎样才能获得最小值呢,如果k是最大负数,那么把最大正i给k显然会得到最小情况,同理类推,用一种非常贪婪的思路去考虑当前的最优解决方案(贪心greedy),发现刚好是倒序排列乘以i即可。有人说马老师,你这不严谨,我说这很严谨。不信,你试试。
最后就是手写排序,考虑qsort过题,不懂的建议百度或者自己看看头文件的重载。如果能力允许手写快排也不是问题哈。选择排序据说可以过。
(一个小时不到,主要是想思路和推导这个结论)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int x[5][100004];
int ar[100005];
int cmp(const void* a, const void * b) {
	return (*(int*)a - *(int*)b);
}//这里就是排序的比较,从大到小或者从小到大就是由他决定的

int main() {
	long long ans = 0;
	long long n;
	scanf("%lld", &n);
	for (long long  i = 1;i <= n;i++) {
		scanf("%d%d%d", &x[1][i], &x[2][i], &x[3][i]);
		ar[i-1] = x[1][i] + x[3][i] - x[2][i];
		ans += x[1][i] + n * x[2][i] +  x[3][i]*2;//把已经确定的内容加起来,减少时间复杂度
		//printf("%d", x[i][0]);
	}
	qsort(ar,n,sizeof(int),cmp);//快速排序在c语言中,头文件stdlib.h
	long long i = 0;
	while (n) {
	//很多人问我while(n) if(n)是怎么回事,其实就是括号内纯数字的情况下,判定是否为0,如果不是,那就是真,如果是,那就是假(即跳出循环或者判定)
		ans += n * ar[i++];
		n--;
	}
	printf("%lld\n", ans);
	return 0;
}

题四:老板和红玉海(思维题)

题意:未知m天,n*m的值减去卑微红渴望天数的总数值>=m。应该简单的吧。这个想法的话要特判某人的最大期望值。(总耗时二十五分钟)(写的差不多了才想出结论,不过过题不影响)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<string.h>
long long x[200005];
long long sum=0;
int main()
{
	long long n,ans=0;
	scanf("%lld", &n);
	for (long long  i = 1;i <= n;i++) {
		
		scanf("%lld", &x[i]);
		if (ans < x[i]) {
			ans = x[i];
		}
		sum += x[i];//判定最大值用于特判
	}
	if ( n * ans-sum >= ans)printf("%lld\n", ans);
	else for (long long i = 1;i <= 2e9;i++) {
		if (sum - (n-1) * i <= (n - 1) * ans)
		{
     //这里的if可以优化成我的那个思路,感兴趣的同学可以手动移项
			printf("%lld\n", i + ans);
			break;
		}
	}
	return 0;//完美收官
}

题五:老板与水晶都(未写出代码)

题意:给两条平行线,如果所有点分布在两条线上则通过。(必须有至少一点过一线)
伪代码理解:只要相邻的点的斜率计算结果只有2-3种情况就可以了。
伪代码2理解:四个点以内必然成立。
我不敢苟同,可能我才疏学浅无法理解他们的想法,所以不深究,我比较笨,就当思维题解了,比较k值,比较b值,他怎么说我怎么做,做出来是啥就是啥。代码也不贴了,因为感觉有题读歪的倾向(不确定是不是数据的问题)

跳过 大森林和伊尔美格,目前没有能力完成。

题六:老板和延夏

签到题,贪心(在前面云计算有介绍一点点贪心的意思),最少硬币显然是先考虑100,再以此类推。(用时三分钟)

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
	long long n;
	scanf("%lld", &n);
	while (n--) {
		long long x;
		scanf("%lld", &x);
		long long ans = 0;
		//这四行代码直接复制粘贴,然后第一行手写
		ans += x / 100;
		ans += (x % 100) / 20;
		ans += (x % 20) / 10;
		ans += (x % 10)/5;
		ans += x % 5;
		printf("%lld\n", ans);
	}
	return 0;
}

题七:老板与克卢西亚岛

这题有人问优化复杂度保证过题。
我一看,是1e5。好家伙,我直接好家伙。
那么问题来了,这题应该如何提高效率一遍做出来呢?
脑内模拟这个过程,很清晰,l进0号房,l进1号房,r进9号房,r进9号房,1一号房退房。
那么就一次只读一个字符,然后执行这个字符的操作即可。Getchar就可以满足这个条件。然后遍历10个房间,l从0往9,r从9往0,碰到0就退出循环(break)并标记为1.如果是数字就直接拿数字去进入对应的房间(数组)消掉1变为0呗。耗时二十分钟

#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
	int n,m,x;
	x = 0;
	int flag = 0;
	char a[100008];
	int b[100];
	//同样是让空间清零的做法,给出一个不同的角度方便各位学习
	//缺点,时间复杂度是on,,比较不太好
	for (int i = 0;i < 10;i++) b[i] = 0;
	scanf("%d", &n);
	for (int i = 1;i <= n;i++)
	{
	//这里我选择用%c去读scanf的值,主要是照顾水平不够的选手
		scanf("\n%c", &a[i]);//前面打一个\n防止吃进回车
		if ((int)a[i] >= '0' && (int)a[i] <= '9') b[(int)a[i] - '0'] = 0;
		else if (a[i] == 'L') {
			for (int j = 0;j <= 9;j++) {
				if (b[j] == 0)
				{
					b[j] = 1;
					break;
				}
			}
		}
		else if(a[i]=='R'){
			for (int j = 9;j >= 0;j--) {
				if (b[j] == 0) {
					b[j] = 1;
					break;
				}
			 }
	 	   } 
	}
	for(int i=0;i<=9;i++)
	printf("%d",b[i]);
	return 0;
}

题八:老板与艾兰

这题也是简单思维题,先考虑能摆放的数字是不是大于等于2并且不相同,如果是直接输出yes,如果相同或者1就看数字是否小于0左边的非零数字或者大于0右边的非零数字。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
	int n,m,x;
	x = 0;
	int flag = 0;
	int a[1000], b[1000],c[1000];
	scanf("%d%d", &n,&m);
	for (int i = 0;i < n;i++)
	{
		scanf("%d", &a[i]);
		if (a[i] == 0) c[x++] = i;
	}
	for (int i = 0;i < m;i++) {
		scanf("%d", &b[i]);
		}
	for (int i = 0;i < x - 1;i++) {
		for (int j = 0;j < m;j++) {
			if (a[c[i] - 1] > b[j] || a[c[i] + 1] < b[j]) flag = 1;
		}
	}
	if (flag) printf("Yes\n");
	else printf("No\n");
	return 0;
}

提前总结,最后一题留下次

动态规划那题已经做出来了,但感觉不叫做出来,叫默出答案了,题目是模板的动态规划,抄代码都能过的那种。只需要预处理数据即可。
其他题目新生组确实难度上只是比这次的段考难上一些,不存在断档的情况。
主要也是为了照顾新生组不至于全场爆零吧。
也希望各位能认真学习c语言,然后多想想代码与代码的那些事,会加深理解。
千言万语一句话, 多写题,多看代码,少玩手机。
我知道你们也不会听的

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值