SCAU2023秋季赛新生受苦记录(C语言)

文章讲述了作者解决编程题目的过程,包括提取数字回文中的回文判断、计算质数串中第n个数字、验证科拉茨猜想、确定球队名次以及判断圆和矩形是否重叠。作者分享了代码实现、思路调整和优化技巧,同时吐槽了遇到的问题和学习经验。
摘要由CSDN通过智能技术生成

概述

感觉都是正常想就能写出来的题 我的过提顺序是ABCED(没错就写了五题) 这也是刚学半年C的小筎蒻第一次写文章 有什么意见和改进方向尽管提喵

A 数字回文

题目

有一个字符串中嵌入了 1~9 的数字,字符串中包含的字符个数小于 10,且字符不为空 格、制表符等空白字符。请从左到右取出这些数字组成一个新的数字字符串,然后判断该 数字字符串是否为回文?如果是回文,输出“Yes”,否则输出“No”。

思路

就是取数字字符出来放到一个新字符串里然后判断回文 直接写也不会爆 签到题 上代码

代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        char s[20],a[20];
        scanf("%s",s);
        int n=strlen(s);
        int j=0;
        for(int i=0; i<n; i++)
        {
            if(isdigit(s[i]))
            {
                a[j]=s[i];
                j++;
            }
        }
        int flag=1;
        for(int i=0; i<=j/2; i++)
        {
            if(a[i]!=a[j-1-i])
            {
                flag=0;
                break;
            }
        }
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

吐槽

一开始样例上写的YES和NO都是大写但是数据点里都是小写 我因为这个错了一次 刚交完就通知说第一题题面有错误让刷新

还有就是我把isdigit打成isalpha错了半天找不到问题在哪

B 质数串

题目

从 2 开始的质数如下: 2 3 5 7 11 13…… 如果将质数按顺序合并为一个长长的数字串就得到: 23571113…… 现在问这个串第 n 个数字是什么?以及该数字来源于哪一个质数?

思路

提前写俩数组 a[n]存第n个数来自哪个素数 b[n]存第n个数是啥数 直接在读入case之前搞定 姑且有点个dp的感觉 注意循环次数 容易爆 题目的数据刚好卡在要超时的临界位置

代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int isPrime(int a)//因为我从2开始遍历所以就懒得对1加判断了
{
    if(a==2)
        return 1;
    for(int i=2;i<=sqrt(a);i++)
    {
        if(a%i==0)
            return 0;
    }
    return 1;
}

int main()
{
    int a[100010],b[100010];
    int i=1;
    for(int num=2;i<=100010;num++)
    {
        if(isPrime(num))
        {
            int time=1;//time是倍数的意思 不是时间!
            while(time<num)
                time*=10;
            time/=10;
            int now=num;
            while(now>0)
            {
                a[i]=num;
                b[i]=now/time;
                now=now%time;
                time/=10;
                i++;
            }
        }
    }
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int haohaohao;
        scanf("%d",&haohaohao);
        printf("%d %d\n",b[haohaohao],a[haohaohao]);
    }
    return 0;
}

吐槽

那道题先兴高采烈地把下面的读取输入写好的 为了防止写忘了把字母重复利用了所以写了个巨长的 只能说好好好

C 测试科拉茨猜想

题目

著名的科拉茨猜想提出:任取一个正整数,如果这个数是偶数,则除以 2。如果是奇数, 乘以 3 再加 1。结算结果重复上述步骤,最后起始数都会变成 1。 科拉茨猜想看起来十分简单,但是证明却无从下手。现在邀请大家编程检验一百万以内的 正整数的科拉茨猜想是否成立,如果给定的正整数最后会变成 1,请给出计算的次数(称为 正整数的科拉茨计算次数);如果不能变成 1,返回-1。 例如:正整数 3 的科拉茨计算次数为 7:3->10->5->16->8->4->2->1。

思路

最简单的一题 while(1)计数到1就break就完事了 我当时也是这么写的 现在想看看能不能用递归实现一下子

代码

循环版

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a;
        scanf("%d",&a);
        int count=0;
        while(1)
        {
            if(a==1)
                break;
            if(a%2==0)
                a/=2;
            else
                a=a*3+1;
            count++;
        }
        printf("%d\n",count);
    }
    return 0;
}

递归版

#include <stdio.h>
#include <stdlib.h>
int f(int a)
{
    if(a==1)
        return 0;
    if(a%2==0)
        return f(a/2)+1;
    return f(a*3+1)+1;
}

int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int a;
        scanf("%d",&a);
        printf("%d\n",f(a));
    }
    return 0;
}

D 输出球队的名次

题目

描述

甲、乙、丙三位球迷分别预测已进入半决赛的四队 A、B、C、D 的名次如下:

甲预测:A 第 1 名,B 第 2 名;

乙预测:C 第 1 名,D 第 3 名;

丙预测:D 第 2 名,A 第 3 名。

比赛结果,甲、乙、丙预测各对一半。试求 A、B、C、D 四队名次,如果能求出,那么输 出它们的名次,可能不止一种情况(按 a,b,c,d,名次数小的先排先输出);否则输 出“No”。

输入格式

多组 Case,读入到文件末尾结束 每组 Case 一行 6 个数,按甲、乙、丙顺序,输入他们的预测名次用整数 1~4,用空格分隔。

输出格式

每个 Case: 按 A、B、C、D 的顺序输出它们的名次,按字典序从小到大输出所有可能。

输入样例

1 2 1 3 2 3

1 2 1 2 1 2

输出样例

a=3,b=2,c=1,d=4

No

思路

一开始我感觉遍历的话情况太多算不过来(我现在自己听我这想法我都觉得蠢) 于是按人脑想法开始模拟 发现代码好长情况好多懒得打 而且搞完了我还得排字典序 回过头来才发现遍历轻松杀 那还说啥啊 都浪费那么多时间了 赶紧写就完事了 上代码

特别注意:每人的猜测都对一半说明一个猜测是对的而另一个猜测一定是错的

代码

#include <stdio.h>
#include <stdlib.h>

int main()
{
    while(1)
    {
        int a1,b1,c2,d2,d3,a3;
        scanf("%d%d%d%d%d%d",&a1,&b1,&c2,&d2,&d3,&a3);
        int flag=1;//这个是判断我要不要输出No的
        for(int a=1;a<=4;a++)
        {
            for(int b=1;b<=4;b++)
            {
                for(int c=1;c<=4;c++)
                {
                    for(int d=1;d<=4;d++)
                    {
                        if(a==b||a==c||a==d||b==c||b==d||c==d)
                            continue;//四个球队的名次肯定不会有重复对伐
                        //下面是主体喵
                        if(a==a1&&c==c2&&d==d3&&b!=b1&&d!=d2&&a!=a3){
                            printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);flag=0;continue;}
                        if(a!=a1&&c==c2&&d==d3&&b==b1&&d!=d2&&a!=a3){
                            printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);flag=0;continue;}
                        if(a==a1&&c!=c2&&d==d3&&b!=b1&&d==d2&&a!=a3){
                            printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);flag=0;continue;}
                        if(a==a1&&c==c2&&d!=d3&&b!=b1&&d!=d2&&a==a3){
                            printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);flag=0;continue;}
                        if(a!=a1&&c!=c2&&d==d3&&b==b1&&d==d2&&a!=a3){
                            printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);flag=0;continue;}
                        if(a==a1&&c!=c2&&d!=d3&&b!=b1&&d==d2&&a==a3){
                            printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);flag=0;continue;}
                        if(a!=a1&&c==c2&&d!=d3&&b==b1&&d!=d2&&a==a3){
                            printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);flag=0;continue;}
                        if(a!=a1&&c!=c2&&d!=d3&&b==b1&&d==d2&&a==a3){
                            printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d);flag=0;continue;}
                    }
                }
            }
        }
        if(flag)
            printf("No\n");
    }
    return 0;
}

吐槽

那个文件输入直到结束我是真搞不来 一直搞EOF啥的发现总是会把最后一个case无限输出 最后直接写while(1)反而可以了 这一段我是真搞不明白

因为flag是后加的嘛 当时加的时候直接写在continue后面了 所以无论如何最后总是会多输出一个No 就这么个玩意儿我找了半天 靠

E 圆和矩形是否有重叠

题目

给定以 (r, x, y) 表示的圆和一个与坐标轴平行的矩形 (x1, y1, x2, y2),其中 r 是圆 的半径长度, x, y 是圆心的坐标; (x1, y1) 是矩形左下角的坐标,而 (x2, y2) 是右上 角的坐标。

如果圆和矩形有重叠的部分,请返回 1 ,否则返回 0 。

注意,请检测是否存在点 (xi, yi),它既在圆上也在矩形上(两者都包括点落在边界上的情况)。

举例 1:

输入:r = 1, x = 0, y = 0, x1 = 1, y1 = -1, x2 = 3, y2 = 1

输出:1

解释:圆和矩形存在公共点 (1,0) 。

举例 2:

输入:r = 1, x = 1, y = 1, x1 = 1, y1 = -3, x2 = 2, y2 = -1

输出:0

思路

最最最最最一开始没想什么数学方式 咱们直接遍历 就写成了这个样子

#include <stdio.h>
#include <stdlib.h>
long long max(long long a,long long b)
{
    if(a>=b)
        return a;
    else
        return b;
}
long long min(long long a,long long b)
{
    if(a>=b)
        return b;
    else
        return a;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long r,x,y,x1,y1,x2,y2;
        scanf("%lld%lld%lld%lld%lld%lld%lld",&r,&x,&y,&x1,&y1,&x2,&y2);
        long long shang=max(y+r,y2),xia=min(y-r,y1),zuo=min(x-r,x1),you=max(x+r,x2);
        int isBreak=0;
        for(long long i=zuo;i<=you;i++)
        {
            for(long long j=xia;j<=shang;j++)
            {
                if((x-i)*(x-i)+(y-j)*(y-j)<=r*r&&i>=x1&&i<=x2&&j>=y1&&j<=y2)
                {
                    isBreak=1;
                    break;
                }
            }
            if(isBreak)
                break;
        }
        printf("%d\n",isBreak);
    }
    return 0;
}

结果发现TLE了喵(当然样例数据是能跑出来的 你可以试试)

那就改呗 开始研究数学

一开始我想的是比较复杂的 用了各种各样的表达式 加了一堆if判断 就是满足这些条件就可以认定这个圆和矩形有重叠使得flag=1喵 但是永远无法概括出所有的情况 总是会错误

这个时候我们不妨反其道而行之 默认是能重叠 满足一些条件就不能重叠 再让flag=0

这样就很好想了:如果圆的最下面一个点都在矩形上方 那应该就肯定不重叠了喵 其他三个方向也是同理

很好 那我们就开始写吧

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long r,x,y,x1,y1,x2,y2;
        scanf("%lld%lld%lld%lld%lld%lld%lld",&r,&x,&y,&x1,&y1,&x2,&y2);
        int flag=1;
        if(x+r<x1)
            flag=0;
        else if(x-r>x2)
            flag=0;
        else if(y-r>y2)
            flag=0;
        else if(y+r<y1)
            flag=0;
        printf("%d\n",flag);
    }
    return 0;
}

很好 样例测试一下也能过 自信提交! “错误”!

那我们再仔细地想一想 是不是有这样一种情况 在上面的判断中会是有重叠 但是实际上并没有

所以嘛 我们还要对矩形的顶点加判断

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long r,x,y,x1,y1,x2,y2;
        scanf("%lld%lld%lld%lld%lld%lld%lld",&r,&x,&y,&x1,&y1,&x2,&y2);
        int flag=1;
        if(x+r<x1)
            flag=0;
        else if(x-r>x2)
            flag=0;
        else if(y-r>y2)
            flag=0;
        else if(y+r<y1)
            flag=0;
        if((x-x1)*(x-x1)+(y-y1)*(y-y1)>r*r)
            flag=0;
        else if((x-x1)*(x-x1)+(y-y2)*(y-y2)>r*r)
            flag=0;
        else if((x-x2)*(x-x2)+(y-y1)*(y-y1)>r*r)
            flag=0;
        else if((x-x2)*(x-x2)+(y-y2)*(y-y2)>r*r)
            flag=0;
        printf("%d\n",flag);
    }
    return 0;
}

OK再测试一下 这次发现连样例都过不了了 出大问题

发现判断顶点有一个前提 就是我的圆心得在左上/左下/右上/右下角 如果圆心在侧面那完全有可能是别的情况让我有重叠

最后改一下提交就过了喵

代码

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long r,x,y,x1,y1,x2,y2;
        scanf("%lld%lld%lld%lld%lld%lld%lld",&r,&x,&y,&x1,&y1,&x2,&y2);
        int flag=1;
        if(x+r<x1)
            flag=0;
        else if(x-r>x2)
            flag=0;
        else if(y-r>y2)
            flag=0;
        else if(y+r<y1)
            flag=0;
        if((x-x1)*(x-x1)+(y-y1)*(y-y1)>r*r&&x<x1&&y<y1)
            flag=0;
        else if((x-x1)*(x-x1)+(y-y2)*(y-y2)>r*r&&x<x1&&y>y2)
            flag=0;
        else if((x-x2)*(x-x2)+(y-y1)*(y-y1)>r*r&&x>x2&&y<y1)
            flag=0;
        else if((x-x2)*(x-x2)+(y-y2)*(y-y2)>r*r&&x>x2&&y>y2)
            flag=0;
        printf("%d\n",flag);
    }
    return 0;
}

总结

OK那以上就是我的第一篇文章 希望能对你有所帮助(感觉也只帮助得到大一的新生哈)

后面的题应该会有转载官方题解的吧 我这就是个个人向记录而已

在可能会有的下一篇文章再见喵~

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值