6793. 【2014广州市选day1】倒数运算

63 篇文章 0 订阅
12 篇文章 0 订阅

Description

倒数,顾名思义就是用1除以被倒数得出的结果,例如2的倒数是0.5,0.5的倒数是2。现在我们需要获得正有理数的倒数。
 
正有理数的表示格式:
  <整数部分> + [小数点]+ [小数非循环部分] [(循环部分)]
其中 <> 为必填部分, []为可选部分, 如果选了小数点,则后面肯定有小数部分
 
   正有理数的表示要求:
整数部分十位数字以后不能有多余的0,如  00123 是非法的有理数
小数后面不能有多余的0,如  0.123000  , 0.12(0)  是非法的有理数
可以放进循环部分的小数一定要放进循环部分,不能留在非循环部分,如  0.123(3) ,12.123234(234) 是非法的
小数循环部分不能是 (9),如果是(9)则需要进一处理,如 0.(9)=1 , 0.2(9)=0.3 

Input

输入只有一行,代表一个正有理数,符合上述的有理数表示要求,每一行最多100个字符。

Output

输出一行,代表输入的正有理数的倒数,要求符合上述有理数的表示要求。
输入数据保证输出的正确答案不超过100个字符。
 

Sample Input

Sample Input1
3

Sample Input2
0.(3)
 

Sample Output

Sample Output1  
0.(3)

Sample Output2
  3
 

Solution

高精度。

对于循环节之前的部分,写成a/b的形式,a,b为整数,b为10的非负整数次方。

对于循环节部分,设X=0.0000(abcde),设S=0.(abcde),

则10^5S=abcde.(abcde)

10^5S-S=99999S=abcde

S=abcde/99999

X=S/10^4

这样就能表示出来了。

设循环节可以写成c/d

那么答案=1/(a/b+c/d)=1/( (ad+bc) / bd )=bd/(ad+bc)

先除一遍,输出整数部分。

如果如数为0则停止;

如果不为0,则:

          再将小数点后面的部分乘以10^100,

          再除一遍,

          如果余数为0则直接省略最后面的0输出;

          如果不为0,枚举一段数作为循环节,判断和下一段连续的数是否相等,知道找到循环节为止。时间复杂度是三次方。

          

Code

#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
#define I int
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define mem(a,b) memset(a,b,sizeof a)
#define N 1000
#define M 10
using namespace std;
I a[N],b[N],c[N],d[N],t[N],p,len,bz;
char s[N];
void up(I o[]){
	F(i,1,o[0]){o[i+1]+=o[i]/M;o[i]%=M;}
	while(o[o[0]+1]){
		o[0]++;
		o[o[0]+1]+=o[o[0]]/M,o[o[0]]%=M;
	}
}
void time(I o[]){F(i,1,o[0]) o[i]*=10;}
void TM(I A[],I B[]){
	mem(t,0);
	t[0]=A[0]+B[0]-1;
	if(!A[0]||!B[0]) t[0]=0;
	F(i,1,A[0]){
		F(j,1,B[0]){
			t[i+j-1]+=A[i]*B[j];
			t[i+j]+=t[i+j-1]/M;
			t[i+j-1]%=M;
		}
	}
	up(t);
}
I cmp(I A[],I B[]){
	if(A[0]>B[0]) return 1;
	if(A[0]<B[0]) return 0;
	Fd(i,A[0],1){
		if(A[i]>B[i]) return 1;
		if(A[i]<B[i]) return 0;
	}
	return 1;
}
void dec(I C[],I T[]){
	F(j,1,T[0]) C[j]-=T[j];
	F(j,1,T[0]){
		while(C[j]<0){C[j]+=M,C[j+1]--;}
	}
	while(C[0]&&!C[C[0]]) C[0]--;
}
void div(){
	mem(c,0);mem(d,0);
	Fd(i,b[0],1){
		time(c);c[1]+=b[i];up(c);
		Fd(j,9,0){
			mem(t,0);
			t[0]=a[0];
			F(k,1,a[0]) t[k]=a[k]*j;
			up(t);
			if(cmp(c,t)){d[i]=j;dec(c,t);break;}
		}
	}
	d[0]=b[0];
	while(!d[d[0]]) d[0]--;
}
I main(){
	freopen("numdiv.in","r",stdin);
	freopen("numdiv.out","w",stdout);
	scanf("%s",s+1),len=strlen(s+1);
	F(i,1,len){
		if(s[i]=='.') p=i;if(s[i]=='(') bz=i;
		if(s[i]=='.'||s[i]=='('||s[i]==')') continue; 
		if(bz){time(c),c[1]+=s[i]-'0',up(c);}
		else{time(a),a[1]+=s[i]-'0',up(a);}
	}
	b[0]=b[1]=1;
	I tim=bz?bz-p-1:(p?len-p:len-1);
	while(tim--){time(b),up(b);}
	if(bz){
		tim=len-bz-1;
		while(tim--){time(d);d[1]+=9;up(d);}
		tim=bz-p-1;
		while(tim--){time(d);up(d);}
	}
	else d[0]=d[1]=1;
	TM(a,d);F(i,0,t[0]) a[i]=t[i];//a*d
	TM(c,b);F(i,0,t[0]) c[i]=t[i];//c*b
	a[0]=max(a[0],c[0]);F(i,1,c[0]) a[i]+=c[i];up(a);//a*d+c*b
	TM(b,d);F(i,0,t[0])	b[i]=t[i];//b*d
	//ans=b/a
	if(cmp(b,a)){ //b>=a
		div();
		Fd(i,d[0],1) printf("%d",d[i]);
		TM(d,a);dec(b,t);
		if(!b[0]) return 0;
		else printf(".");
	}
	else printf("0.");
	F(i,1,100){time(b);up(b);}
	div();
	if(!c[0]){
		len=1;
		while(!d[len]) len++;
		Fd(i,100,len) printf("%d",d[i]);
		return 0;		
	}
	Fd(i,100,1){
		Fd(j,i,1){
			len=i-j+1;
			bz=1;
			F(k,1,len) if(d[i-k+1]!=d[j-1-k+1]){bz=0;break;}
			if(bz){
				Fd(k,100,i+1) printf("%d",d[k]);
				printf("(");
				Fd(k,i,j) printf("%d",d[k]);
				printf(")");
				return 0;
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值