本题的要求很简单,就是求N
个数字的和。麻烦的是,这些数字是以有理数分子/分母
的形式给出的,你输出的和也必须是有理数的形式。
输入格式:
输入第一行给出一个正整数N
(≤100)。随后一行按格式a1/b1 a2/b2 ...
给出N
个有理数。题目保证所有分子和分母都在长整型范围内。另外,负数的符号一定出现在分子前面。
输出格式:
输出上述数字和的最简形式 —— 即将结果写成整数部分 分数部分
,其中分数部分写成分子/分母
,要求分子小于分母,且它们没有公因子。如果结果的整数部分为0,则只输出分数部分。
输入样例1:
5
2/5 4/15 1/30 -2/60 8/3
输出样例1:
3 1/3
输入样例2:
2
4/3 2/3
输出样例2:
2
输入样例3:
3
1/3 -1/6 1/8
输出样例3:
7/24
以下参考样例来自 L1-009 N个数求和 (20分)【附测试】_晚风吻尽荷叶的博客-CSDN博客
1
-50/1000
结果:-1/20
3
0/1 0/1 0/1
结果:0
5
-1/2 -1/2 -1/2 -1/2 -1/2
结果 :-2 -1/2
最大公约数 gcd
原理: 求a,b的最大公约数
设 a=b*x+c,d=gcd(a,b). [gcd为两数的最大公约数]
由于d是a,b的最大公约数,则b=d*x1、a=d*x1+c=d*x2 (x1、x2为最大公约数所乘系数。如:12 = 6*2 ; 18 = 6*2+6 = 6*3 )
并且 c=a%b,因此 gcd(a,c)=gcd(b,c)=gcd(a,b)
当且仅当c为零的时候,b为最大公约数
/法一:自己写gcd
int gcd(int a,int b){ //求最大公约数,注意类型范围
return b? gcd(b,a%b):a; //第二个数不为0时,继续递归
}
//法二:
algorithm头文件自带 __gcd(a,b);//前面两个下划线,可以返回long long类型的
最小公倍数lcm
int lcm(int a,int b){
return a/__gcd(a,b)*b; //a,b相乘除以最大公约数;此方法较优,因为a和b直接相乘可能超
范围
}
题目提及所有数字在长整型以内,所以用long long 作为数据类型
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
ll s[105][2];
ll lcm(ll a , ll b){
return a/__gcd(a,b)*b;
}
int main()
{
int n ;
ll gcd , lcmlcm=1;;
cin>>n;
for(int i=0;i<n;i++){
scanf("%lld/%lld",&s[i][0],&s[i][1]);
lcmlcm=lcm(lcmlcm,s[i][1]); //计算分母的最小公倍数
}
ll numerator=0;
for(int i=0;i<n;i++){
s[i][0]=s[i][0]*(lcmlcm/s[i][1]);
numerator += s[i][0]; //将分子乘以最小公倍数与分母的商后加起来,算出分子和
}
if(!numerator){ //分子和为零时直接输出并结束
cout<<"0"<<endl;
return 0;
}
if(abs(numerator/lcmlcm) >1 && numerator%lcmlcm!=0) //分数不为整数且绝对值大于1时
{
cout<<numerator/lcmlcm<<" ";
numerator -= (numerator/lcmlcm)*lcmlcm;
}else if(abs(numerator/lcmlcm) >= 1 && numerator%lcmlcm==0){ //分数为整数时
cout<<numerator/lcmlcm<<endl;
return 0;
}
if(numerator){ //分数部分
gcd = __gcd(lcmlcm,numerator);
lcmlcm /= gcd;
numerator /= gcd;
printf("%d/%d\n",numerator,lcmlcm);
}
return 0;
}