解题报告-NYIST大一新生赛(10.16)

从1(签到)到5(防AK)标下难度
难度1,2的都应该会做,难度为3的多写一道出来就说明学得不错

A - 分拆素数和(难度 3)
首先筛法打出一万以内的素数(学筛法可以戳这里
对于给定的N,要求出两个不同素数相加等于N的组合数量,直接枚举2到N/2的所有数,如果这个数i是素数,再判断N-i是不是素数,如果是的话,那就找到了一个组合。为了防止出现重复的组合,只能枚举2~N/2而不是2~N

#include<stdio.h>
#include<math.h>
#include<string.h>
#define maxn 10005
//素数筛法
int is_Prime[maxn];//是素数的标记为0
void Prime()//筛法打表
{
    memset(is_Prime,0,sizeof(is_Prime));//假设全是素数
    is_Prime[1]=1;//1不是素数
    for(int i=2; i<=sqrt(maxn); i++)
    {
        if(is_Prime[i]==0)
        {
            for(int j=2; i*j<=maxn; j++)
            {
                is_Prime[i*j]=1;
            }
        }
    }
}
int main()
{
    int N;
    Prime();//筛法预处理
    while(~scanf("%d",&N)&&N)
    {
        int result=0;
        for(int i=2; i<N/2; i++)//要求是两个不同素数,所以只需要找前半段就可以了
            if(is_Prime[i]==0&&is_Prime[N-i]==0)
                result++;
        printf("%d\n",result);
    }
    return 0;
}

B - 求平均成绩(难度 3)
开一个浮点型矩阵,横行存储一个学生的各科成绩,纵列存储一个学科的各学生成绩。
每横行末尾存储该学生的各科平均成绩,没纵列末尾存储该科目各学生平均分。

坑点:两个数之间有空格,末尾没有空格,一组数据全部输出后再输出空行

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
using namespace std;
int main()
{
    int N,M;
    while(~scanf("%d%d",&N,&M))
    {
        double num[55][55];
        memset(num,0,sizeof(num));
        for(int i=1; i<=N; i++)
        {
            for(int j=1; j<=M; j++)
            {
                scanf("%lf",&num[i][j]);
                num[i][M+1]+=num[i][j];//行尾记录某一学生所有科目总分
            }
            num[i][M+1]=num[i][M+1]/(M*1.0);//行尾记录某一学生各科平均分
        }
        for(int j=1; j<=M; j++)
        {
            for(int i=1; i<=N; i++)
            {
                num[N+1][j]+=num[i][j];//列尾记录某一课程所有学生的总分
            }
            num[N+1][j]=num[N+1][j]/(N*1.0);//列尾记录某一课程所有学生的平均分
        }
        int result=0;//记录所有科目均超过该科目所有学生平均分的学生数量
        for(int i=1; i<=N; i++)
        {
            bool flag=0;//如果第i行的同学不符合条件就标记为1
            for(int j=1; j<=M; j++)
            {
                if(num[i][j]<num[N+1][j])
                {
                    flag=1;
                    break;
                }
            }
            if(flag==0)
                result++;
        }
        for(int i=1; i<N; i++)//注意空格输出
            printf("%.2lf ",num[i][M+1]);
        printf("%.2lf\n",num[N][M+1]);
        for(int j=1; j<M; j++)
            printf("%.2lf ",num[N+1][j]);
        printf("%.2lf\n",num[N+1][M]);
        printf("%d\n\n",result);
    }
}

C - 手机短号(难度 1)
实力签到题,花式做法很多

#include<stdio.h>
#include<string.h>
#include<math.h>
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        char str[100];
        scanf("%s",str);
        printf("6");
        for(int i=6;i<=10;i++)
            printf("%c",str[i]);
        printf("\n");
    }
    return 0;
}

D - 找单词(难度 5)
防AK难题,做不出不要急,以后学了动态规划或者组合数学就可以做了
先给出动态规划的解法(动态规划不会?下个月再学都不迟)
DP[i][j]代表前i个字母组合出j价值的方法数量是DP[i][j]
状态转移方程:DP[i][j]=DP[i-1][j],DP[i][j]+=DP[i-1][j-i*k];

还可以用组合数学中构造母函数的方法,这里先不讲,等学过组合数学自然就会了。

#include<stdio.h>
#include<math.h>
#include<string.h>
int main ()
{
    int T;
    scanf ("%d", &T);
    while (T--)
    {
        int num[27];
        int DP[27][55];
        memset(DP,0,sizeof(DP));
        for(int i=0; i<=26; i++)
            DP[i][0]=1;

        for(int i=1; i<=26; i++)
            scanf ("%d",&num[i]);

        for(int i=1; i<=26; i++)
            for(int j=1; j<=50; j++)
            {
                DP[i][j]=DP[i-1][j];
                for (int k=1; k<=num[i]&&j-i*k>=0; k++)
                    DP[i][j]+=DP[i-1][j-i*k];
            }

        int ans=0;
        for (int i=1; i<=50; i++)
            ans+=DP[26][i];
        printf("%d\n",ans);
    }
    return 0;
}

E - 夹角有多大(题目已修改,注意读题)(难度 3)
秒针会影响分针,分针会影响时针,时针注意转化为十二小时制

#include<stdio.h>
#include<math.h>
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        double h,m,s;
        scanf("%lf%lf%lf",&h,&m,&s);
        if(h>12)//转化成十二小时制
            h-=12;
        m+=s/60;//六十秒相当于一分钟
        double angle1=m*360/60;//分针转的度数
        h+=m/60;//一小时相当于六十分钟
        double angle2=h*360/12;//分针转的度数
        double ans=fabs(angle1-angle2);//分针转动导致时针也在动
        if(ans>180)
            ans=360-ans;
        printf("%d\n",(int)ans);
    }
    return 0;
}

F - 查找最大元素(难度 2)
接收完数据后,遍历一遍字符串找到最大字符并记录,再遍历输出时检测输出的当前字符是否为最大字符,如果是最大字符就再多输出(max)

#include<stdio.h>
#include<math.h>
#include<string.h>
int main()
{
    char str[105];
    while(~scanf("%s",str))
    {
        int len=strlen(str);
        char c=str[0];
        for(int i=0; i<len; i++)//遍历字符串找到最大字符
            if(str[i]>c)
                c=str[i];
        for(int i=0; i<len; i++)//遍历输出
        {
            printf("%c",str[i]);
            if(str[i]==c)//如果输出的是最大字符
                printf("(max)");
        }
        printf("\n");
    }
    return 0;
}

G - 小明A+B(难度 1)
涉及到同余定理,百度百科传送门

#include<stdio.h>
#include<math.h>
#include<string.h>
//同余定理
//(a%c+b%c)%c==(a+b)%c
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        long long int a,b;//这里是坑
        scanf("%I64d%I64d",&a,&b);
        printf("%I64d\n",(a+b)%100);
    }
    return 0;
}

H - 夹角有多大II(难度 2)
纯计算几何,不会做的问高中数学课代表
下面的代码仅供参考

#include <stdio.h>
#include <math.h>
#define pi 3.1415926
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        double x1,x2,y1,y2,t,a,b,c;
        scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
        a = sqrt(x1*x1+y1*y1);
        b = sqrt(x2*x2+y2*y2);
        c = sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
        t = (a*a+b*b-c*c)/(2.0*b*a);
        t = acos(t)*180/pi;
        while(t>180)
            t-=180;
        printf("%.2lf\n",t);
    }
    return 0;
}

I - 整数解(难度 2)
对于X+Y=N,X*Y=M,可以消元带入化简为一元二次方程,然后利用求根公式判断得到的结果是否合法。
懒省劲的我直接暴力枚举,什么求根公式,好麻烦。

#include <stdio.h>
#include <math.h>
//还可套公式
int main()
{
    int a,b;
    while(scanf("%d%d",&a,&b))
    {
        if(a==0&&b==0)
            break;
        bool flag=false;//初始化为假,找到解了就标记为真
        for(int i=-10001;i<=10001;i++)//枚举x
        {
            if(i*(a-i)==b)//a-i是y
            {
                flag=true;
                break;//找到解就标记然后结束循环
            }
        }
        flag==true?printf("Yes\n"):printf("No\n");//这是三目运算符
    }
    return 0;
}

J - 汉诺塔III(难度 4)
轻度防AK的简单动规,其实自己也可以递归推出来的。

对于只有1个圆盘,很明显需要移动3次
对于只有2个圆盘,很明显需要移动3*1+2次
对于只有3个圆盘,很明显需要移动3*(3*1+2)+2次

如果用DP[i]代表有i个圆盘时需要移动的次数为DP[i]
对于只有N个圆盘,需要DP[N-1]*3+2次

状态转移方程:DP[1]=3,DP[N]=DP[N-1]*3+2

#include<stdio.h>
#include<math.h>
#include<string.h>
#define maxn 10005
//简单动规
//状态转移方程:DP[1]=2,DP[N]=DP[N-1]*3+2
int main()
{
    long long int DP[40];
    DP[1]=2;
    for(int i=2;i<=35;i++)
        DP[i]=DP[i-1]*3+2;
    int N;
    while(~scanf("%d",&N))
    {
        printf("%I64d\n",DP[N]);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值