L1-009 N个数求和
本题的要求很简单,就是求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
这道题花了好久时间 讲讲自己的思路吧
#include<stdio.h>
#define N 1000
long long get(long long a,long long b){//辗转相除法求最大公约数
long long t;
while(b){
t=a%b;
a=b;
b=t;
}
return a;
}
long long a[N];
long long b[N];//开辟数组a放分子,b放分母
// a[0]=1;
int main(){
int n;
int x;
x=0;
// a[0]=1;
scanf("%d",&n);
long long t=1;
//这里就是我神奇的脑回路:先把第一个分母当成最大公倍数然后和后面一个分母求最小公倍数,将前面 //的一个分母更新成最大公倍数 这样遍历就得到最小公倍数
for(int i=1;i<=n;i++){
scanf("%lld/%lld",&a[i],&b[i]);
if(i==1){
b[0]=b[1];
x=get(b[i],b[i-1]);//最大公约数
t=b[i]*b[i-1]/x;//最小公倍数
}else{
x=get(b[i],t);//最大公约数t和a[i]求最大公约数
t=b[i]*t/x; //最小公倍数
}
}
long long sum;
sum=0;
for(int i=1;i<=n;i++){//遍历求分子
a[i]=a[i]*(t/b[i]);
sum+=a[i];
}
//这里就是输出部分 做得很糟糕 而且在算出分子分母之后没有再约分!增加了工作量
//做到后面发现要让负号在前面 所以在每一条if语句里面都加了sum<0的语句判断 但是测试点3死活过不了
if(sum%t==0){//如果是整数
printf("%lld",sum/t);return 0;
}else{
if(t%(sum%t)==0){//如果可以约分
if(sum/t==0){//整数位为0 // sum%t是份子
if(sum<0) printf("-1/%d",(t/(sum%t))*(-1));
else printf("1/%d",t/(sum%t));
}
else {
if(sum<0) printf("-1/%lld",(t/(sum%t))*(-1));
else printf("%lld 1/%lld",sum/t,t/(sum%t));
}
}else {
if(sum/t==0) {//整数位为0
if(sum<0) printf("-1/%lld",(sum%t)*(-1));
else printf("%lld/%lld",sum%t,t);
}
else {
if(sum<0) printf("%lld -1/%lld",sum/t,(t/(sum%t))*(-1));
else printf("%lld %lld/%lld",sum/t,sum%t,t);
}
}
}
}
后面是改进版本 能过可能是测试点不够全面吧 用一些特殊的还是和理想情况不一致
#include<stdio.h>
#define N 1000
long long get(long long a,long long b){
long long t;
while(b){
t=a%b;
a=b;
b=t;
}
return a;
}
long long a[N];
long long b[N];
// a[0]=1;
int main(){
int n;
int x;
x=0;
// a[0]=1;
scanf("%d",&n);
long long t=1;
//if(n==0)return 0;
for(int i=1;i<=n;i++){
scanf("%lld/%lld",&a[i],&b[i]);
if(i==1){
b[0]=b[1];
x=get(b[i],b[i-1]);//最大公约数
t=b[i]*b[i-1]/x;//最小公倍数
}else{
x=get(b[i],t);//最大公约数t和a[i]求最大公约数
t=b[i]*t/x; //最小公倍数
}
}
long long sum;
sum=0;
for(int i=1;i<=n;i++){
a[i]=a[i]*(t/b[i]);
sum+=a[i];
} //我采用的思路是先全部通分后相加。这样大概率会超出给定的数据范围
//t是最小公倍数 即分母 分子是sum
//约分
long long r=get(t,sum);
sum/=r,t/=r;
//这里的判断相比我之前的会简单很多 因为已经约分过一次了
if(sum%t==0)printf("%lld",sum/t);
else{
//如果分子大于分母
if(sum/t)printf("%lld ",sum/t);//这个判断方式是真的妙!默认输出后面的部分 因为不管分母和分子直接大小关系如何
//都是必须要输出的
// printf("%lld/%lld",sum-sum/t*t,t);
printf("%lld/%lld",sum%t,t); //用这一行输出的时后用5 -1/2 -1/2 -1/2 -1/2 -1/2的时候会输出-2 1/-2 负号 //在后面但是上面那一行就不会 输出好像没有对负号在上下有限制
}
}
#include<stdio.h>
#define N 1000
long long get(long long a,long long b){
long long t;
while(b){
t=a%b;
a=b;
b=t;
}
return a;
}
long long sumup,sumdown=1;
int main(){
int n;
int x;
x=0;
long long a,b,t=0;
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%lld/%lld",&a,&b); //对求和的方式优化 一边求和一边遍历这样就不会超出数据范围
//先通分再约分
sumup=sumup*b+a*sumdown;
sumdown=sumdown*b;
t=get(sumup,sumdown);
sumup/=t;
sumdown/=t;
}
if(sumup%sumdown==0)printf("%lld",sumup/sumdown);
else{
//如果分子大于分母
if(sumup/sumdown)printf("%lld ",sumup/sumdown);
printf("%lld/%lld",sumup-sumup/sumdown*sumdown,sumdown);
// printf("%lld/%lld",sum%t,t);
}
}
总结:
1.对大数的相加时尽量先处理数据让数据变小一点这样不会超出数据范围
2.对于多种条件输出的时候可以先默认输出必须要的,然后在进行判断
mup/sumdown)printf(“%lld “,sumup/sumdown);
printf(”%lld/%lld”,sumup-sumup/sumdown*sumdown,sumdown);
// printf(“%lld/%lld”,sum%t,t);
}
}
## 总结:
1.对大数的相加时尽量先处理数据让数据变小一点这样不会超出数据范围
2.对于多种条件输出的时候可以先默认输出必须要的,然后在进行判断