日常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语言,然后多想想代码与代码的那些事,会加深理解。
千言万语一句话, 多写题,多看代码,少玩手机。
我知道你们也不会听的