Bootstrap

c/c++学习——高精度

深入浅出学算法017-高精度求N!
题目描述
用高精度方法,求N!的精确值(N以一般整数输入)。
输入
输入一个整数n( 1<= n <= 350)
输出
输出n!
样例输入
10
样例输出
3628800

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main()
{
	ll a[2000],n,s,b,j,i;
	cin>>n;
	memset(a,0,sizeof(a));//数组清零
	a[0]=1;
	for(i=1; i<=n; i++)
	{
		b=0;
		for(j=0; j<2000; j++)
		{
			s=a[j]*i+b;//每一项的值
			a[j]=s%10;//余数
			b=s/10;//要进的数
		}

	}
	for(j=2000-1; j>=0; j--)
	{
		if(a[j]) break;//删除多余前导0
	}
	for(i=j; i>=0; i--)
	{
		cout<<a[i];
	}
	return 0;
}

深入浅出学算法018-求A/B高精度值
题目描述
计算A/B的精确值,设A,B是以一般整数输入,计算结果精确小数后20位
(若不足20位,末尾不用补0) 。
输入
输入2个普通的整数A和B
输出
输出A/B的值,保留20位小数,如果不足20位,末尾不用补0,格式见样例
样例输入 Copy
【样例1】
4 3
【样例2】
6 5
样例输出 Copy
【样例1】
4/3=1.33333333333333333333
【样例2】
6/5=1.2

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main()
{
	int r,x[21],i=0;
	long long a,b;
	cin>>a>>b;
	printf("%lld/%lld=%d.",a,b,a/b);
	r=a%b;
	memset(x,0,sizeof(x));
	if(r==0) cout<<'0';
	while(r!=0&&i<=19)
	{
		r*=10;//商乘以10,模拟竖式除法
		x[i]=r/b;
		i++;
		r%=b;
	}
	for(i=19;i>=0;i--){
		if(x[i]!=0)
		{
		break;//防止循环小数或者无限不循环小数的20位或者后面几位是0
		}
	}
	for(int j=0;j<=i;j++){
		cout<<x[j];
	}
	return 0;
}

深入浅出学算法019-求n累加和
题目描述
用高精度方法,求s=1+2+3+……+n的精确值(n以一般整数输入)。
输入
输入一个整数n(n<=1000000)
输出
输出累加和
样例输入 Copy
10
样例输出 Copy
55

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main(){
	ll n,i,j=0,x=1,a[50];
	cin>>n;
	memset(a,0,sizeof(a));
	for(i=1;i<=n;i++){
		j=0;
		a[j]+=i;
		while(a[j]>=10){
			a[j+1]+=a[j]/10;//高位数加上前面低位数进的值
			a[j]%=10;//进位后剩下的值
			j++;
		}
	}
	for(i=40;i>=0;i--) if(a[i]) break;//删除多余前导0
	for(j=i;j>=0;j--) cout<<a[j];
	return 0;
}

深入浅出学算法020-阶乘和(sum)
题目描述
已知正整数N(N<=100),设S=1!+2!+3!+…N!。其中"!"表示阶乘,即N!=123*……(N-1)N,如:3!=123=6。请编程实现:输入正整数N,输出计算结果S的值。
输入
输入一个整数n( 1<= n<=100)

输出
输出s的值
样例输入 Copy
4
样例输出 Copy
33

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
	ll n,c,i,j,x,k,y=0,a[2020],b[2020];
	cin>>n;
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	a[0]=1;
	for(i=1; i<=n; i++)
	{
		c=0;
		for(j=0; j<2020; j++)
		{
			x=a[j]*i+c;//每位数的乘积加上前面进位的数
			c=x/10;//进位的数
			a[j]=x%10;//进位后剩下的数
			b[j]+=a[j];//阶乘后相加
			while(b[j]>=10)
			{
				b[j+1]+=b[j]/10;高位数加上前面低位数进的值
				b[j]%=10;//进位后剩下的数
			}
		}
	}
	for(j=2018; j>=0; j--) if(b[j]) break;//删除多余前导0
	for(i=j; i>=0; i--) cout<<b[i];
	return 0;
}

深入浅出学算法021-高精度求积(MULTIPLY)
题目描述
输入两个高精度非负整数M和N(M和N均小于100位)。
输入
输入两个高精度非负整数M和N(M和N均小于100位)。
输出
求这两个高精度数的积。
样例输入 Copy
36
3
样例输出 Copy
108

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main(){
	ll i,j,b,n[200],m[200],s,k=-1,a[2000];
	char n1[200],m1[200];
	cin>>n1>>m1;
	ll x=strlen(n1);
	ll y=strlen(m1);
	memset(a,0,sizeof(a));
	memset(n,0,sizeof(n));
	memset(m,0,sizeof(m));
	for(i=0;i<x;i++) n[i]=n1[i]-'0';
	for(i=0;i<y;i++) m[i]=m1[i]-'0';
	int o=0;
	for(i=x-1;i>=0;i--){
	o=x-i-1;b=0;//o表示从a数组的第一位开始	
		for(j=y-1;j>=0;j--){
			s=m[j]*n[i]+b;//竖式乘法每项相加
			b=s/10;//进位的数
			a[o]=a[o]+s%10; //加上进位的数
			if(a[o]>=10){//考虑相加后仍然有大于10的数
				a[o+1]+=a[o]/10;
				a[o]%=10;
			} 
			o++;
		}
		if(b!=0) a[o]+=b;//最后一项单独拿出来,因为上面的循环没了
	}
	
	for(i=1999;i>0;i--) if(a[i]) break;
	for(j=i;j>=0;j--){
		cout<<a[j];
	}
	return 0;
}

1327: 深入浅出学算法022-天使的起誓
题目描述
Tenshi非常幸运地被选为掌管智慧之匙的天使。在正式任职之前,她必须和其他新当选的天使一样要宣誓。
宣誓仪式是每位天使各自表述自己的使命,他们的发言稿放在n个呈圆形排列的宝盒中。这些宝盒按顺时针方向被编上号码1,2,…,n-1,n。
一开始天使们站在编号为n的宝盒旁。她们各自手上都有一个数字,代表她们自己的发言稿所在的盒子是从1号盒子开始按顺时针方向的第几个。例如:有7个盒子,如果Tenshi手上的数字为9,那么她的发言稿所在的盒子就是2个。现在天使们开始按照自己手上的数字来找发言稿,先找到的就可以先发言。
Tenshi一下子就找到了,于是她最先上台宣誓:“我将带领大家开启Noi之门……” Tenshi宣誓结束后,陆续有天使上台宣誓。可是有一位天使找了好久都找不到她的发言稿,原来她手上的数字m非常大,她转了好久都找不到她想找的宝盒。
请帮助这位天使找到她想找的宝盒编号。
输入
第一行为正整数n,第二行为正整数m,其中n,m满足2<=n<=108,2<=m<=101000
输出
只有一行(包括换行符),即天使想找的宝盒的编号。
样例输入 Copy
【输入样例1】
7
9
【输入样例2】
11
108
样例输出 Copy
【输出样例1】
2
【输出样例2】
9

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main()
{
	char m[2000];
	ll s,x,b,a[2000],n,i,j;
	cin>>n>>m;
	memset(a,0,sizeof(a));
	x=strlen(m);
	for(i=0; i<x; i++) a[i]=m[i]-'0';
	b=0;
	s=a[0];
	for(i=0; i<x; i++)//模拟竖式除法,取余
	{
		s=b*10+a[i];
		b=s%n;	
	}
	if(b==0) b=n;//考虑到m刚好是n的倍数
	cout<<b;
	return 0;
}

1328: 深入浅出学算法023-汉诺双塔
题目描述
给定A、B、C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形)。

现要将这些圆盘移到C柱上,在移动过程中可放在B柱上暂存。要求:
(1)每次只能移动一个圆盘;
(2)A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
任务:设An为2n个圆盘完成上述任务所需的最少移动次数,对于输入的n,输出An。

输入
一个正整数n,表示在AA柱上放有2n个圆盘。
输出
一个正整数, 为完成上述任务所需的最少移动次数An。
样例输入 Copy
【输入样例1】
1
【输入样例2】
2
样例输出 Copy
【输出样例1】
2
【输出样例2】
6
提示
【限制】
对于50%的数据,1≤n≤25
对于100%的数据,1≤n≤200
【提示】
设法建立An与An−1的递推关系式

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
	ll n,x,i=0,j,a[2000];
	cin>>n;
	memset(a,0,sizeof(a));
	while(n--)
	{
		for(i=0; i<2000; i++) a[i]*=2;//这两步是An和An-1的关系
		a[0]+=2;//An=2*An-1+2
		for(i=0; i<2000; i++)
		{
			if(a[i]>=10)
			{
				a[i+1]+=a[i]/10;
				a[i]=a[i]%10;
			}
		}
	}
	for(i=1999; i>=0; i--)
	{
		if(a[i]) break;
	}
	for(j=i; j>=0; j--)
	{
		cout<<a[j];
	}
	return 0;
}

1329: 深入浅出学算法024-回文数
题目描述
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个十进制数56,将56加65(即把56从右向左读),得到121是一个回文数。
又如:对于十进制数87:
STEP1:87+78 = 165
STEP2:165+561 = 726
STEP3:726+627 = 1353
STEP4:1353+3531 = 4884
在这里的一步是指进行了一次N进制的加法,上例最少用了4步得到回文数4884。
写一个程序,给定一个N,2≤N≤10,N=16)进制数M(100位之内),求最少经过几步可以得到回文数。如果在30步以内(包含30步)不可能得到回文数,则输出Impossible!
输入
两行,分别是N,M。
输出
STEP=ans
样例输入 Copy
10
87
样例输出 Copy
STEP=4

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main()
{
	ll n,a[9000],x,b[9000],i,j=0,flag=0,count=0;
	char m[200];
	cin>>n>>m;
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	x=strlen(m);
	for(i=0; i<x; i++)
	{
		if(m[i]<='9'&&m[i]>=0) a[i]=m[i]-'0';
		if(m[i]>='a'&&m[i]<='z') a[i]=m[i]-'a'+10;//考虑到16进制
		if(m[i]>='A'&&m[i]<='Z') a[i]=m[i]-'A'+10;
	}
	for(i=0; i<x; i++)
	{
		if(a[i]!=a[x-i-1])//判断回文
		{
			for(j=0; j<x; j++) b[j]=a[j];
			for(j=0; j<x; j++)
			{
				a[j]+=b[x-j-1];
				if(a[j]>=n)
				{
					a[j+1]+=a[j]/n;
					a[j]%=n;
				}
			}
			flag=1;
			count++;
			if(count>=30){
				flag=2;//次数大于等于三十
			}
		}
		if(flag==2) break;
		if(flag==1)
		{
			for(int c=8999; c>=0; c--)//删除多余前导零
			{
				if(a[c])
				{
					flag=0;
					x=c+1;
					i=0;
					break;
				}
			}
		}
	}
	if(flag==2) cout<<"Impossible!"<<endl;
	else cout<<"STEP="<<count<<endl;
	return 0;
}

1330: 深入浅出学算法025-斐波那切数列
题目描述
斐波那切数列0,1,1,2,3,5,8,13,21,34,55……从第三项起,每一项都是紧挨着的前两项的和。写出计算斐波那切数列的任意一个数据项递归程序。
输入
输入所求的项数。
输出
输出数据项的值。
样例输入 Copy
10
样例输出 Copy
34

#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
	int n,i,j,k=0,a[3000],b[3000],c[3000];
	cin>>n;
	memset(a,0,sizeof(a));//a数组表示Fn-2
	memset(b,0,sizeof(b));//b数组表示Fn-1
	memset(c,0,sizeof(c));//c数组表示Fn
	b[0]=1;
	a[0]=0;
	if(n>=3)
		for(i=3; i<=n; i++)
		{
			for(j=0;j<=2999;j++){
				c[j]=a[j]+b[j]+k;//数组相加
				k=0;             
				if(c[j]>=10){
					k=c[j]/10;
					c[j+1]+=c[j]/10;
					c[j]%=10;
				}
			}
			for(j=2999;j>=0;j--){
				a[j]=b[j];//函数向前进一位
				b[j]=c[j];
			}
		}
		for(i=2999;i>=0;i--) if(c[i]) break;
		if(n>=3) for(i;i>=0;i--) cout<<c[i];
		if(n==2) cout<<1;
		if(n==1) cout<<0;
	return 0;
}


1331: 深入浅出学算法026-倒序数
题目描述
用递归算法写程序,输入一个非负整数,输出这个数的倒序数。
输入
输入一个非负整数。
输出
输出倒序结果。
样例输入 Copy
123
样例输出 Copy
321

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main(){
	char a[5000];
	ll b[5000],i;
	cin>>a;
	for(i=0;a[i]!='\0';i++) b[i]=a[i]-'0';//把每个数字分开
	i--;
	for(;i>=0;i--) cout<<b[i];
	return 0;
}

1332: 深入浅出学算法027-十进制转换成八进制
题目描述
用递归算法,把任一给定的十进制正整数转换成八进制数输出。
输入
输入一个正整数,表示需要转换的十进制数。
输出
输出一个正整数,表示转换之后的八进制的数。
样例输入 Copy
15
样例输出 Copy
17

#include <bits/stdc++.h>
#define ll long long
using namespace std;

int main()
{
	ll a[3000],y=0,c[3000],s,b=0,i,j,flag=1;
	char m[3000];
	cin>>m;
	memset(a,-1,sizeof(a));
	memset(c,0,sizeof(c));
	for(i=0; m[i]!='\0'; i++) a[i]=m[i]-'0';//输入十进制数
	while(1)
	{
		flag=1;
		for(j=2999; j>=0; j--) if(a[j]!=-1) break;//删除多余的后面的数
		for(i=0; i<=j; i++)
		{
			s=a[i]+b*10;
			a[i]=s/8;
			b=s%8;
			flag+=s;//检测是否全部除完
		}
		if(flag==1) break;//全部除完,跳出循环
		c[y]=b;//记录商
		y++;
		b=0;
	}
	for(i=2999; i>=0; i--) if(c[i]!=0) break;//删除多余前导零
	for(j=i; j>=0; j--) cout<<c[j];//输出八进制数
	return 0;
}


;