2018/11/02 ACM集训第三次周赛题解及自身题目优化

问题 A: 珠心算测试
题目描述
珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术。珠心算训练, 既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普及。 某学校的珠心算老师采用一种快速考察珠心算加法能力的测验方法。他随机生成一个正 整数集合,集合中的数各不相同,然后要求学生回答:其中有多少个数,恰好等于集合中另 外两个(不同的)数之和? 最近老师出了一些测验题,请你帮忙求出答案。

输入
输入共两行,第一行包含一个整数 n,表示测试题中给出的正整数个数。
第二行有 n 个正整数,每两个正整数之间用一个空格隔开,表示测试题中给出的正整数。

输出
输出共一行,包含一个整数,表示测验题答案。

样例输入

4
1 2 3 4

样例输出

2

提示
【样例说明】
由 1+2=3,1+3=4,故满足测试要求的答案为 2。注意,加数和被加数必须是集合中的 两个不同的数。

【数据说明】
对于 100%的数据,3 ≤ n ≤ 100,测验题给出的正整数大小不超过 10,000。

分析:这个题中有的陷阱在于,一个数有可能会是集合中两组数的和,如1,2,3,4,5中1+4=5,2+3=5,这个地方错了两遍,都是因为在这儿要不是多减就是少减了。蓝受香菇。இ௰இ最后是用了另一个数组来储存已经出现过一次的数,从而避免重复。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,a[105];
	scanf("%d",&n);
	int i;
	for(i=0;i<n;i++)
	{
		scanf("%d",&a[i]);
	}
	int item=0;
	int b[100];
	int x=0;
	for(i=0;i<n-1;i++)
	for(int k=i+1;k<n;k++)
	{
		for(int t=0;t<n;t++)
		{
			if(a[i]+a[k]==a[t])
			{
				if(b[t]==a[t]) 
				item--;
				b[t]=a[t]; 
				item++;
				break;
			}
		}
	}
	printf("%d",item);
	return 0;
}

问题B:比例简化
题目描述
在社交媒体上,经常会看到针对某一个观点同意与否的民意调查以及结果。例如,对某 一观点表示支持的有 1498 人,反对的有 902 人,那么赞同与反对的比例可以简单的记为 1498:902。 不过,如果把调查结果就以这种方式呈现出来,大多数人肯定不会满意。因为这个比例 的数值太大,难以一眼看出它们的关系。对于上面这个例子,如果把比例记为 5:3,虽然与 真实结果有一定的误差,但依然能够较为准确地反映调查结果,同时也显得比较直观。 现给出支持人数 A,反对人数 B,以及一个上限 L,请你将 A 比 B 化简为 A’比 B’,要 求在 A’和 B’均不大于 L 且 A’和 B’互质(两个整数的最大公约数是 1)的 前提下,A’/B’ ≥ A/B 且 A’/B’ - A/B 的值尽可能小。

输入
输入共一行,包含三个整数 A,B,L,每两个整数之间用一个空格隔开,分别表示支持 人数、反对人数以及上限。

输出
输出共一行,包含两个整数 A’,B’,中间用一个空格隔开,表示化简后的比例。

样例输入

1498 902 10 

样例输出

5 3

提示
【数据说明】
对于 100%的数据,1 ≤ A ≤ 1,000,000,1 ≤ B ≤ 1,000,000,1 ≤ L ≤ 100, A/B ≤ L。

分析:
这个题目没做粗来,很痛苦,,后来看了题解后发现,并没有特别地难,首先要求在 A’和 B’均不大于 L 且 A’和 B’互质(两个整数的最大公约数是 1)的前提下,所以先要考虑已给出的数据是否满足这一情况,所以要求粗两个数据的最大公约数
到这里,看了林姐的题解后,学到了通过递归函数来求gcd的方法。

int gcd(int a,int b)
{
	return b==0?a:gcd(b,a%b);
}

如果给出的数据不满足条件,因为数据比较小,所以可以直接暴力求解。利用两个循环来求满足条件的数,A’/B’ ≥ A/B 且 A’/B’ - A/B 的值尽可能小,可将式子转换为A’B ≥ AB’,A’/B’ - A/B 的值尽可能小,也可用上面的公式。

#include<bits/stdc++.h>
using namespace std;
int gcd(int a,int b)
{
	return b==0?a:gcd(b,a%b);
}
int main()
{
	int A,B;
	int g;
	int L;
	scanf("%d%d%d",&A,&B,&L);
	int x=A,y=B;
	g=gcd(A,B);
	if(A/g<=L&&B/g<=L)
	{
		printf("%d %d",A/g,B/g);
		return 0;
	}
	else
	{
		int x=1000001,y=1;
		int i,k;
		for(i=1;i<=L;i++)
		{
			for(k=1;k<=L;k++)
			{
				if(i*B>=k*A)
				{
					if(i*y<k*x)
					{
						x=i;
						y=k;
					}
					
				}
			}
		}
		printf("%d %d",x,y);
	}

	return 0;
}

问题C:螺旋矩阵
题目描述
一个 n 行 n 列的螺旋矩阵可由如下方法生成: 从矩阵的左上角(第 1 行第 1 列)出发,初始时向右移动;如果前方是未曾经过的格子, 则继续前进,否则右转;重复上述操作直至经过矩阵中所有格子。
根据经过顺序,在格子中 依次填入 1, 2, 3, … , n 2 ,便构成了一个螺旋矩阵。
下图是一个 n = 4 时的螺旋矩阵。

现给出矩阵大小 n 以及 i 和 j,请你求出该矩阵中第 i 行第 j 列的数是多少。

输入
输入共一行,包含三个整数 n,i,j,每两个整数之间用一个空格隔开,分别表示矩阵 大小、待求的数所在的行号和列号。

输出
输出共一行,包含一个整数,表示相应矩阵中第 i 行第 j 列的数。

样例输入

4 2 3

样例输出

14

提示
【数据说明】
对于 50%的数据,1 ≤ n ≤ 100; 对于 100%的数据,1 ≤ n ≤ 30,000,1 ≤ i ≤ n,1 ≤ j ≤ n。

分析:在这个题中,我将每个矩阵的一圈的数字写成了一个函数,并利用函数的自身调用来实现矩阵内层的数计算,直至矩阵坐标为输入时的要求停止。我将矩阵的列设为x,行设为y,按照顺时针的顺序进行坐标变化和数自增1.转完一圈后为函数运行一遍,然后用以n-1的圈为单位,2,2坐标开始运行。过程比较麻烦,可能还有更简便的。

#include<bits/stdc++.h>
using namespace std;
int num=1;
int x=1,y=1,k=1;
void NUM(int a,int b,int c,int k)
{
   if(x==c&&y==b)
   {
   	printf("%d",num);
   	return;
   }
   while(x<a)
   {
   		if(x==c&&y==b)
   	{
   		printf("%d",num);
   		return;
   	}
   	x++;
   	num++;
   }
   while(y<a)
   {
   		if(x==c&&y==b)
   	{
   		printf("%d",num);
   		return;
   	}
   	y++;
   	num++;
   }
   while(x>k)
   {
   		if(x==c&&y==b)
   	{
   		printf("%d",num);
   		return;
   	}
   	x--;
   	num++;
   }
   while(y>k)
   {
   		if(x== c&&y == b)
   	{
   		printf("%d",num);
   		return;
   	}
   	y--;
   	num++;
   	if(y == k&&x ==k)
   	{
   		x++;
   		y++;
   		k++;
   	}
   }
   NUM(a-1,b,c,k);
   
}
int main()
{
   int a[100][100];
   int n,i,j;
   scanf("%d%d%d",&n,&i,&j);
   int x,y;
   NUM(n,i,j,k);
   return 0;
}

问题D:子矩阵(待解决)
题目描述
给出如下定义: 1. 子矩阵:从一个矩阵当中选取某些行和某些列交叉位置所组成的新矩阵(保持行与 列的相对顺序)被称为原矩阵的一个子矩阵。 例如,下面左图中选取第 2、4 行和第 2、4、5 列交叉位置的元素得到一个 2*3 的子矩 阵如右图所示。
在这里插入图片描述
2. 相邻的元素:矩阵中的某个元素与其上下左右四个元素(如果存在的话)是相邻的。
3. 矩阵的分值:矩阵中每一对相邻元素之差的绝对值之和。 本题任务:给定一个 n 行 m 列的正整数矩阵,请你从这个矩阵中选出一个 r 行 c 列的 子矩阵,使得这个子矩阵的分值最小,并输出这个分值。

输入
第一行包含用空格隔开的四个整数 n,m,r,c,意义如问题᧿述中所述,每两个整数 之间用一个空格隔开。 接下来的 n 行,每行包含 m 个用空格隔开的整数,用来表示问题描述中那个 n 行 m 列 的矩阵。

输出
输出共 1 行,包含 1 个整数,表示满足题目描述的子矩阵的最小分值。

样例输入
5 5 2 3
9 3 3 3 9
9 4 8 7 4
1 7 4 6 6
6 8 5 6 9
7 4 5 6 1

样例输出
6

提示
【输入输出样例 说明】
该矩阵中分值最小的 2 行 3 列的子矩阵由原矩阵的第 4 行、第 5 行与第 1 列、第 3 列、第 4 列交叉位置的元素组成,

6 5 6
7 5 6
其分值为 6 − 5 + 5 − 6 + 7 − 5 + 5 − 6 + 6 − 7 + 5 − 5 + 6 − 6 = 6。

问题E:计数问题
题目描述
试计算在区间 1 到 n 的所有整数中,数字 x(0 ≤ x ≤ 9)共出现了多少次?例如,在 1 到 11 中,即在 1、2、3、4、5、6、7、8、9、10、11 中,数字 1 出现了 4 次。

输入
输入共 1 行,包含 2 个整数 n、x,之间用一个空格隔开。

输出
输出共 1 行,包含一个整数,表示 x 出现的次数。

样例输入
11 1

样例输出
4

提示
【数据说明】
对于 100%的数据,1≤ n ≤ 1,000,000,0 ≤ x ≤ 9。
分析:直接将数的各个位拆开,出现一个要求统计的数字就计数一次。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n,x;
	int i,item=0;
	int a;
	scanf("%d%d",&n,&x);
	for(i=1;i<=n;i++)
	{
		a=i;
		while(a!=0)
		{
			if(x==a%10)
			item++;
			a=a/10;
		}
	}
	printf("%d",item);
	
	return 0;
}

问题F:表达式求值
题目描述
给定一个只包含加法和乘法的算术表达式,请你编程计算表达式的值。

输入
输入仅有一行,为需要你计算的表达式,表达式中只包含数字、加法运算符“+”和乘 法运算符“*”,且没有括号,所有参与运算的数字均为 0 到 2^31 -1 之间的整数。
输入数据保 证这一行只有 0~ 9、+、*这 12 种字符。

输出
输出只有一行,包含一个整数,表示这个表达式的值。
注意:当答案长度多于 4 位时, 请只输出最后 4 位,前导 0 不输出。

样例输入
1+1*3+4

样例输出
8

提示
样例 计算的结果为 8,直接输出 8。

【数据范围】
对于 30%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100;
对于 80%的数据,0≤表达式中加法运算符和乘法运算符的总数≤1000;
对于 100%的数据,0≤表达式中加法运算符和乘法运算符的总数≤100000。
分析:这个题没有做出来,因为错在没有想到如何做到先乘后加的实现方法,,菜啊?,后来结束后就像出来了,输入一个数后,再输入一个字符,判断字符的类型如果是‘\n’,结束程序,如果是乘则将前面的一个元素与下一个元素相乘直至出现加号,而相乘后前面的那个元素就可以变为0;最后把数组中所有元素相加。

#include<bits/stdc++.h>
using namespace std;
int main()
{
	long long a[100005];
	char b;
	int i=0;
	scanf("%lld",&a[i]);
	a[i]=a[i]%10000;
	i++;
	while(1)
	{
		b=getchar();
		if(b=='\n')
			break;
		if(b=='*')
		{
			scanf("%lld",&a[i]);
			a[i]%=10000;
			a[i]=a[i-1]*a[i]%10000;//所有元素相乘
			a[i-1]=0;//前一个元素为0
			i++;
		}
		if(b=='+')
		{
			scanf("%lld",&a[i]);
			a[i]=a[i]%10000;
			i++;
		}
	}
	long long sum=0;
	for(int k=0;k<i;k++)
	{
		sum=(sum+a[k])%10000;
	}
	printf("%lld",sum);
	return 0;
 } 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值