算法协会19级第二次招新【正式赛】题解

比赛链接
passwordHPUACMAC

A - 阿星的图像旋转 (计蒜客 - T1137)

输入一个 n 行 m 列的黑白图像,将它顺时针旋转 90 度后输出。
输入格式
第一行包含两个整数 n 和 m,表示图像包含像素点的行数和列数。1≤n≤100,1≤m≤100。
接下来 n 行,每行 m 个整数,表示图像的每个像素点灰度。相邻两个整数之间用单个空格隔开,每个元素均在 0 ~ 255 之间。
输出格式
m 行,每行 n 个整数,为顺时针旋转 90 度后的图像。相邻两个整数之间用单个空格隔开。
输出时每行末尾的多余空格,不影响答案正确性。
样例输入
3 3
1 2 3
4 5 6
7 8 9
样例输出
7 4 1
8 5 2
9 6 3

#include<cstdio>
using namespace std;
int main()
{
	int n,m;
	scanf("%d%d",&n,&m);
	int a[101][101];
	/*输入*/
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			scanf("%d",&a[i][j]);
	/*输出*/
	for(int j=1;j<=m;j++)
	{
		for(int i=1;i<=n;i++)
		{
			if(i==1)	printf("%d",a[n-i+1][j]);
			else	printf(" %d",a[n-i+1][j]);
		}
		printf("\n");
	}
}

这样的方法正确是正确,但思考时间长,可能更适合把旋转后的数组存储到另一个数组中,再对新的数组进行输出的题目(但是acm里应该不会出现这样的要求吧)。看学长的讲解后,明白了最后的输出部分还可以有更简便的方法:

for(int j=1;j<=m;j++)
{
	for(int i=n;i>=1;i--)
		printf("%d ",a[i][j]);
	printf("\n");
}

形象一点看图(此时n=2m=4):
A


B - 阿星的数字查重 (AtCoder - abc154_c)

Problem Statement
现在给你一个有N个正整数的数组,如果数组中的元素两两不相同就输出YES,否则输出NO
Constraints
2 ≤ N ≤ 200000,1 ≤ 元素值 ≤ 1000000000,保证数据都是整数
Input
输入数据会按照下面格式:
第一行为N
第二行N个正整数,相邻正整数会用空格隔开
Output
如果数组中元素两两不相同,就输出 YES; 否则输出 NO.
Sample Input 1
5
2 6 1 4 5
Sample Output 1
YES
Sample Input 2
6
4 1 3 1 6 2
Sample Output 2
NO
Sample Input 3
2
10000000 10000000
Sample Output 3
NO

分析

这道题看似简单,但是很容易超时。可以考虑setsort的做法。

代码
  1. sort做法
    用sort排序后,相同的数字会被放在一起,因此遍历的时候如果有数字重复,只需要比较前后两个数字是否相同,如果数字相同则有重复,如果直到遍历结束都没有找到相同的就说明无重复数字。
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int main()
    {
    	int N,a[200000];
    	scanf("%d",&N);
    	for(int i=0;i<N;i++)
    	scanf("%d",&a[i]);
    	sort(a,a+N);
    	for(int i=1;i<N;i++)
    	{
    		if(a[i]==a[i-1])
    		{
    			printf("NO\n");
    			return 0;
    		}
    	}
    	printf("YES\n");
    	return 0;
    }
    
  2. set做法
    由于集合set有去重功能(元素唯一性),如果有一样的数字输入的话长度不会变,因此最后的长度比N小就说明有重复的数字,若是与N相同则无重复的数字。
    #include<cstdio>
    #include<set> 
    using namespace std;
    int main()
    {
    	int N,t;
    	scanf("%d",&N);
    	set<int> a;
    	for(int i=0;i<N;i++)
    	{
    		scanf("%d",&t);
    		a.insert(t);
    	}
    	if(N==a.size())	printf("YES\n");
    	else	printf("NO\n");
    }
    

C - 阿星的素数研究 (HDU - 2161)

阿星在入门数论学习之前,她选择从研究素数入手。她想请你帮忙写一个程序判断某个数字是否为素数。如果一个数n只能被1和n整除,则数n为素数。但阿星她不喜欢2这个数字,所以她不认为2是素数。所以你的程序在判断素数的时候,如果是2,不能判断成2为素数
Input
多组输入
每个输入行包含一个整数。当读入数据是小于等于0的数,代表输入结束。保证输入数据包含最多250个待判断素数的数字,每个数字小于或等于16000
Output
输出应由每个数字的一​​行组成,其中每行首先列出问题编号,后跟冒号和空格,后跟“yes”或“no”。
Sample Input
1
2
3
4
5
17
0
Sample Output
1: no
2: no
3: yes
4: no
5: yes
6: yes

分析

素数(也叫质数) 是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数。
素数的判断可以是for循环下判断该数x能否被2~根号x整除,若是可以被整除,则它不是素数,可以直接break跳出循环;否则直到最后都没有找到能被整除的数,则它就是素数。
注意输入小于等于0的数代表输入结束;还需注意该题中1和2都被当作不是素数来看了。

代码
#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
	long long x,n=0;
	while(~scanf("%lld",&x)&&(x>0))
	{
		n++;
		int t=1;
		if(x==1||x==2)	t=0;
		for(int j=2;j<int(sqrt(x)+1);j++)
		{
			if(x%j==0)	t=0;
			if(t==0)	break;
		}
		if(t==0)	printf("%d: no\n",n);
		if(t==1)	printf("%d: yes\n",n);
	}
}

D - 阿星的显示器 (CodeForces - 1315A)

题目描述
阿星新买了一台尺寸为a x b显示器,可是发现显示器上有一个像素点(x,y)是坏的。苦恼的她想要在这个显示器上找一个不包含这个坏点的矩形区域,这样的矩形区域阿星认为才是可以使用的部分,现在她想要知道最大能用矩形区域面积是多少,请你帮助她解决这个问题。
显示器的像素点是从(0,0)点开始编号的,像素坏点(x,y) (0 <= x < a, 0 <= y < b )
输入格式
第一行给出一个T (1 <= T <= 10000);代表有多少组数据需要处理,接下来T行就是T组数据.
每组数据仅占一行,包含 4 个整数 a, b, x 和 y (1 <= a, b <= 10000; 0 <= x < a; 0 <= y < b) 表示显示器的尺寸以及坏点的坐标,数据保证 a+b > 2 (e.g. a=b=1 是不可能作为输入数据的).
输出格式
输出T行,每行包含一个整数,表示每组数据的答案。每个答案是该组数据计算后的最大不包含坏点的矩形区域面积.
样例
Input
6
8 8 0 0
1 10 0 3
17 31 10 4
2 1 0 0
5 10 3 9
10 10 4 8
Output
56
6
442
1
45
80

分析

最大的矩形区域面积只有四种情况,可以把四种情况都列出来然后比较一下哪个大。
用实例比较好理解一点:
D由于显示器的像素点是从(0,0)开始的,可能容易混乱,但是画了图之后可以根据具体的实例推断s1~s4的面积应该怎么算。

代码
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int a,b,x,y;
		int s1,s2,s3,s4;
		scanf("%d%d%d%d",&a,&b,&x,&y);
		s1=x*b;
		s2=(a-x-1)*b;
		s3=a*y;
		s4=a*(b-y-1);
		printf("%d\n",max(max(s1,s2),max(s3,s4)));
	}
}

E - 阿星讨厌数 (HDU - 2089)

题目描述
有一种数叫做阿星讨厌数。原因是阿星非常不喜欢4和62。因此她把一个数中带有4和62叫做阿星讨厌数。例如435,1623阿星很讨厌。但6652不在这个范围内,因为这个时候的6和2不是连在一起的。
她现在要算[n,m]之间的有多少个非阿星讨厌数。她但是由于阿星的脑力太过强大,如果她亲自进行计算的话可能会引发所有地球人的脑波异常,造成世界级的危机。所以请你能帮她计算一下,解救全人类。
Input
多组数据输入。
输入每一行两个数n和m(0<n≤m<106)。 如果输入的n和m都是0则代表输入结束。
Output
对于每一组输入,输出一个数,代表整数n到整数m之间之中有多少个数不是她不讨厌的数。
Sample Input
1 100
0 0
Sample Output
80

分析

此题关键在于如何判断数字是否带有4或62,还有n=0,m=0时需跳出循环结束输入。

  • 判断数字
    第一个想法应该是根据数字从前往后逐位判断是否有4,但对于62来说判断起来就显得有些复杂。况且输入的n与m可能有1~5位不等的数字,每个情况都好好考虑的话不仅写的比较麻烦,而且很可能产生错误或思考不全面,因此最好采用其他的方法。
    由于从前往后不太可行,我们就想到了第二种办法——从后往前。就是判断最后一位是否是4或最后两位是否是62,如果不是,则判断倒数第二位或倒数第二三位……,直至数字到头或判断为是。
  • 跳出循环
    跳出循环较为简单,即当满足条件(n=0且m=0)时用break跳出循环。
代码
#include<cstdio>
#include<algorithm>
using namespace std;
bool judge(int x)//判断数字
{
	while(x)
	{
		if(x%10==4)	return 0;
		if(x%100==62)	return 0;
		x=x/10;
	}
	return 1;
}
int main()
{
	int m,n;
	while(~scanf("%d%d",&n,&m))
	{
		if(n==0 && m==0)	break;//跳出循环
		int sum=0;
		for(int i=n;i<=m;i++)
		{
			if(judge(i))	sum++;
		}
		printf("%d\n",sum);
	}
}

F - 阿星的排序困扰 (HDU - 1280)

给定一个包含N(N<=3000)个正整数的序列,每个数不超过5000,对它们两两相加得到的N*(N-1)/2个和,求出其中前M大的数(M<=1000)并按从大到小的顺序排列。
Input
输入可能包含多组数据,其中每组数据包括两行:
第一行两个数N和M,
第二行N个数,表示该序列。
Output
对于输入的每组数据,输出M个数,表示结果。输出应当按照从大到小的顺序排列。
Sample Input
4 4
1 2 3 4
4 5
5 3 6 4
Sample Output
7 6 5 5
11 10 9 9 8

分析

这题容易超限!先对输入的数组a排序,然后选数组a中最大的几个相加存放在数组b中,但并不一定是加起来最大的那几个b。因此还是先加再排序,而不是先排序再加。
此处的排序用到了sort函数,而sort函数是从小到大排序,因此输出的时候是从后往前输出,输出的个数达到所需要的个数后用break跳出循环不再输出。

代码
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
	int N,M,a[3001],b[5000000];//要记得把b开高点
	while(~scanf("%d%d",&N,&M))
	{
		int cnt=0;
		for(int i=0;i<N;i++)
			scanf("%d",&a[i]);
		for(int i=0;i<N;i++)
		{
			for(int j=i+1;j<N;j++)
			{
				b[cnt++]=a[i]+a[j];
			}
		}
		sort(b,b+cnt);//sort排序后是从小到大的
		for(int i=cnt-1;i>=0;i--)
		{
			if(--M==0)
			{
				printf("%d\n",b[i]);
				break;
			}
			else	printf("%d ",b[i]);
		}
	}
}

G - 阿星算最小公倍数 (HDU - 1108)

给定两个正整数,计算这两个数的最小公倍数。
Input
输入包含多组测试数据,每组只有一行,包括两个不大于1000的正整数.
Output
对于每个测试用例,给出这两个数的最小公倍数,每个实例输出一行。
Sample Input
10 14
Sample Output
70

这题套用一下模板就可

  1. gcdlcm的模板
    #include<cstdio>
    using namespace std;
    int gcd(int a,int b)//求最大公约数
    {
    	return b==0?a:gcd(b,a%b);
    }
    int lcm(int a,int b)//求最小公倍数
    {
    	return a*b/gcd(a,b);
    }
    int main()
    {
    	int x,y;
    	while(~scanf("%d%d",&x,&y))
    	{
    		printf("%d\n",lcm(x,y));
    	}
    }
    
  2. 只有lcm的模板
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int lcm(int a,int b)
    {
    	for(int x=max(a,b);x<=a*b;x++)
    	{
    		if(x%a==0 && x%b==0)	return x;
    	}
    	return -1;
    }
    int main()
    {
    	int x,y;
    	while(~scanf("%d%d",&x,&y))
    	{
    		printf("%d\n",lcm(x,y));
    	}
    }
    

H - 阿星走楼梯 (HDU - 2041)

有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法?
Input
输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1<=M<=40),表示楼梯的级数。
Output
对于每个测试实例,请输出不同走法的数量
Sample Input
2
2
3
Sample Output
1
2

分析

由于要计算从1==>M阶的走法,可以从第M阶倒推有几种走法。M阶有两种走法,可以从M-1阶M-2阶走到(当然这里的M需要≥3),而M-1M-2也有它们自己的走法……,因此可以采用递归的思想。
由于初始位置在第一阶,因此不必加上0==>1阶的那一步。1==>2阶只有1种走法(一次跨一步),1==>3阶有两种走法(一次跨一步+一次跨两步)。其他情况只需要递归倒推需要走几步就行。

代码
#include<cstdio>
using namespace std;
int pa(int n)
{
	if(n==2)	return 1;	//第2阶
	else if(n==3)	return 2;	//第3阶
	else if(n>3)	return pa(n-1)+pa(n-2);	//其余情况(除第1阶)
}
int main()
{
	int N,M;
	scanf("%d",&N);
	for(int i=0;i<N;i++)
	{
		scanf("%d",&M);
		printf("%d\n",pa(M));
	}
}

J - 阿星的温暖签到祝福 (计蒜客 - T1008)

蒜头君知道每个字符都有一个对应的 ASCII 码。
现在输入一个 ASCII 码,要求你输出对应的字符。
输入格式
一个整数,即字符的 ASCII 码,保证对应的字符为可见字符。
输出格式
一行,包含相应的字符。
Sample Input
65
Sample Output
A

这题是签到题,比较简单粗暴哈

#include<cstdio>
using namespace std;
int main()
{
	int a;
	scanf("%d",&a);
	printf("%c",a);
	
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值