从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;
}