高精度求N!
题目描述
用高精度方法,求N!的精确值(N以一般整数输入)。
输入
输入一个整数n( 1<= n <= 350)
输出
输出n!
样例输入
10
样例输出
3628800
思路
题目最大要求350!,因此基本的数据类型都会溢出,选择高精度算法,利用数组来存一个数的各个位数,最后输出即可。
代码
#include <bits/stdc++.h>
using namespace std;
int a[1000];
int main(){
int n,i,j,c=0,p;
cin>>n;
if(n==1)
cout<<"1";
else{
a[0]=1; //令个位为1
for(i=2;i<=n;++i){ //阶乘
c=0; //初始化进位
for(j=0;j<1000;++j){ //倒着存
p=a[j]*i+c; //高精度乘法
a[j]=p%10;
c=p/10; //处理进位
}
}
for(i=999;i>=0;--i) //去除后导0
if(a[i]>0)
break;
for(j=i;j>=0;--j) //倒序输出
cout<<a[j];
}
return 0;
}
求A/B高精度值
题目描述
计算A/B的精确值,设A,B是以一般整数输入,计算结果精确小数后20位
(若不足20位,末尾不用补0) 。
输入
输入2个普通的整数A和B
输出
输出A/B的值,保留20位小数,如果不足20位,末尾不用补0,格式见样例
样例输入
【样例1】
4 3
【样例2】
6 5
样例输出
【样例1】
4/3=1.33333333333333333333
【样例2】
6/5=1.2
提示
输出结果如果小数点后只有一个0,需要输出X.0
思路
本题只需要开一个数组,把小数点后面的数存到数组里,逐位输出即可。
代码
#include <bits/stdc++.h>
using namespace std;
int s[21];
int main(){
int a,b,i,j;
cin>>a>>b;
cout<<a<<"/"<<b<<"="<<a/b<<"."; //输出整数部分与小数点
int p=a%b*10; //模拟除法,对余数进行处理
for(i=1;i<=20;++i){ //模拟小数点后的20位
s[i]=p/b; //将每次的商存入数组
p=p%b*10; //更新余数并处理为下一个被除数
}
cout<<s[1]; //小数点后的第1位一定输出
for(i=20;i>1;i--) //后19位去除末尾为0
if(s[i]!=0)
break;
for(j=2;j<=i;++j) //正序输出
cout<<s[j];
return 0;
}
阶乘和(sum)
题目描述
已知正整数N(N<=100),设S=1!+2!+3!+…N!。其中"!"表示阶乘,即N!=123*……(N-1)N,如:3!=123=6。请编程实现:输入正整数N,输出计算结果S的值。
输入
输入一个整数n( 1<= n<=100)
输出
输出s的值
样例输入
4
样例输出
33
思路
题目最大涉及到100!,并要求求和,因此必须用高精度算法来解决,开两个数组a,sum,a数组算从1~n每项的阶乘,sum数组对这些阶乘进行求和,即a数组进行高精度乘法,sum数组进行高精度加法,最后输出sum数组即可。
代码
#include <bits/stdc++.h>
using namespace std;
int a[1000],sum[1000];
void by(int n){ //高精度乘法
int i,j,c=0,p;
a[0]=1;
for(i=2;i<=n;++i){
c=0;
for(j=0;j<1000;++j){
p=a[j]*i+c;
a[j]=p%10;
c=p/10;
}
}
}
void add(){ //高精度加法
int c=0,i,p;
for(i=0;i<1000;++i){
p=sum[i]+a[i]+c;
sum[i]=p%10;
c=p/10;
}
}
int main(){
int n,i,j;
cin>>n;
for(i=1;i<=n;++i){
memset(a,0,sizeof(a)); //对a数组每次都要初始化
by(i); //阶乘
add(); //加
}
for(i=999;i>=0;--i) //去除后导0
if(sum[i]>0)
break;
for(j=i;j>=0;--j) //逆序输出
cout<<sum[j];
return 0;
}
高精度求积(MULTIPLY)
题目描述
输入两个高精度非负整数M和N(M和N均小于100位)。
输入
输入两个高精度非负整数M和N(M和N均小于100位)。
输出
求这两个高精度数的积。
样例输入
36
3
样例输出
108
思路
M,N均小于100位,定义三个数组a,b,c,a数组表示m,b数组表示n,c数组表示两数的积,把c数组逐位输出即可。注:m,n均以字符串的形式读入
代码
#include <bits/stdc++.h>
using namespace std;
string m,n;
int a[110],b[110],c[221];
int main(){
int i,d,e,p=0,j,k;
cin>>m>>n;
d=m.size(); //m的位数
e=n.size(); //n的位数
for(i=d-1;i>=0;--i)
a[d-1-i]=m[i]-'0'; //逆序存m
for(i=e-1;i>=0;--i)
b[e-1-i]=n[i]-'0'; //逆序存n
k=0; //初始化进位k
for(i=0;i<d;++i){ //高精度乘法
for(j=0;j<e;++j){
p=a[i]*b[j]+k;
c[i+j]+=p%10;
k=p/10;
if(c[i+j]>=10){ //进位
c[i+j+1]+=c[i+j]/10;
c[i+j]=c[i+j]%10;
}
}
while(k){ //最高位进位
c[i+e]+=k%10;
k=k/10;
e++; //改变位数
}
}
for(i=220;i>=0;--i) //去除后导0
if(c[i]!=0)
break;
if(i<0) //如果c数组全为0,则积为0
cout<<"0";
else{
for(j=i;j>=0;--j) //逆序输出为积
cout<<c[j];
}
return 0;
}
回文数
题目描述
若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。
例如:给定一个十进制数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
样例输入
10
87
样例输出
STEP=4
思路
判断30次,如果30次均为非回文数,那么退出循环,输出Impossible!;对于每一次判断,如果是回文数,则退出循环,输出STEP=ans,如果不是回文数,使用高精度加法,更新m的值,继续循环判断。
代码
#include <bits/stdc++.h>
using namespace std;
int n;
string m;
bool huiwen(string n){ //判断回文数
bool f=true;
int i;
for(i=0;i<n.size()/2;++i)
if(n[i]!=n[n.size()-1-i])
f=false;
return f;
}
int num(char c){ //字符转数字
if(c>='0'&&c<='9') return c-'0';
else{
switch(c){
case 'A':return 10;
case 'B':return 11;
case 'C':return 12;
case 'D':return 13;
case 'E':return 14;
case 'F':return 15;
}
}
}
char zim(int c){ //数字转字符
if(c>=0&&c<=9) return c+'0';
else{
switch(c){
case 10:return 'A';
case 11:return 'B';
case 12:return 'C';
case 13:return 'D';
case 14:return 'E';
case 15:return 'F';
}
}
}
string add(string a){ //高精度加法
int l=a.size(),i,k,d,p,q,x;
string b=a,s=""; //初始化字符串b,s
reverse(a.begin(),a.end());
d=0; //初始化进位d
p=0;
q=0;
for(i=0;i<l;++i){
p=num(a[i])+num(b[i])+d;
q=p%n;
d=p/n;
s=zim(q)+s; //在字符串头部插入字符
}
while(d){ //判断最高位是否进位
x=d%10;
d=d/10;
s=zim(x)+s; //在字符串头部插入字符
}
return s;
}
int main(){
int i;
cin>>n;
cin>>m;
for(i=0;i<=30;++i){
if(huiwen(m)) //判断回文
break;
m=add(m); //更新m
}
if(i>30) cout<<"Impossible!";
else cout<<"STEP="<<i;
return 0;
}
汉诺双塔
给定A、B、C三根足够长的细柱,在A柱上放有2n个中间有孔的圆盘,共有n个不同的尺寸,每个尺寸都有两个相同的圆盘,注意这两个圆盘是不加区分的(下图为n=3的情形)。
现要将这些圆盘移到C柱上,在移动过程中可放在B柱上暂存。要求:
(1)每次只能移动一个圆盘;
(2)A、B、C三根细柱上的圆盘都要保持上小下大的顺序;
任务:设An为2n个圆盘完成上述任务所需的最少移动次数,对于输入的n,输出An。
输入
一个正整数n,表示在AA柱上放有2n个圆盘。
输出
一个正整数, 为完成上述任务所需的最少移动次数An。
样例输入
【输入样例1】
1
【输入样例2】
2
样例输出
【输出样例1】
2
【输出样例2】
6
提示
【限制】
对于50%的数据,1≤n≤25
对于100%的数据,1≤n≤200
【提示】
设法建立An与An−1的递推关系式
思路
汉诺双塔移动的次数为pow(2,n+1)-2,也可看作F[N]=F[N-1]+2+F[N-1]=2*F[N-1]+2;由于需要处理的数据范围太大,必须使用高精度乘法与高精度加法。定义两个数组a与sum,用a数组模拟乘法,每次×2求可移动次数,把每次的可移动次数求和为总移动次数sum。
代码
#include <bits/stdc++.h>
using namespace std;
int a[205],sum[205];
int main(){
int n,i,j,d,p,k,x;
cin>>n;
a[200]=1; //初始化a数组最后一位
for(i=1;i<=n;++i){
d=0; //初始化进位
for(j=200;j>0;--j){ //高精度乘法
p=a[j]*2+d;
a[j]=p%10;
d=p/10;
}
k=0; //初始化进位
for(j=200;j>0;--j){ //高精度加法
x=a[j]+sum[j]+k;
sum[j]=x%10;
k=x/10;
}
}
for(i=1;i<=200;++i){ //去除前导0
if(sum[i]!=0)
break;
}
for(j=i;j<=200;++j) //正序输出
cout<<sum[j];
return 0;
}
天使的起誓
题目描述
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
输出
只有一行(包括换行符),即天使想找的宝盒的编号。
样例输入
【输入样例1】
7
9
【输入样例2】
11
108
样例输出
【输出样例1】
2
【输出样例2】
9
思路
简单的剩余定理,取余即可,注:余数为0,要输出n,更新余数。另:数据量太大,以字符串的形式读入
代码
#include <bits/stdc++.h>
using namespace std;
int main(){
int n,l,i,s=0;
string m;
cin>>n>>m;
l=m.size(); //m位数
for(i=0;i<l;++i)
s=(s*10+m[i]-'0')%n; //更新余数
if(s==0) cout<<n;
else cout<<s;
return 0;
}
附加
递归求一个数的倒序数
#include <bits/stdc++.h>
using namespace std;
int f(int n){
if(n>=0&&n<10) printf("%d",n);
else{
printf("%d",n%10);
return f(n/10);
}
}
int main(){
int n;
cin>>n;
f(n);
return 0;
}
递归进制转换:十进制转八进制
#include <bits/stdc++.h>
using namespace std;
int f(int n){
if(n/8==0)
return n;
else return f(n/8)*10+n%8;
}
int main(){
int n;
cin>>n;
cout<<f(n);
return 0;
}
递归:双色汉诺塔问题
设A、B、C是3 个塔座。开始时,在塔座A 上有一叠共n 个圆盘,这些圆盘自下而上,由大到小地叠在一起。各圆盘从小到大编号为1,2,……,n,奇数号圆盘着蓝色,偶数号圆盘着红色,如图所示。现要求将塔座A 上的这一叠圆盘移到塔座B 上,并仍按同样顺序叠置。在移动圆盘时应遵守以下移动规则:
规则(1):每次只能移动1 个圆盘;
规则(2):任何时刻都不允许将较大的圆盘压在较小的圆盘之上;
规则(3):任何时刻都不允许将同色圆盘叠在一起;
规则(4):在满足移动规则(1)-(3)的前提下,可将圆盘移至A,B,C 中任一塔座上。
试设计一个算法,用最少的移动次数将塔座A 上的n个圆盘移到塔座B 上,并仍按同样顺序叠置。
对于给定的正整数n,编程计算最优移动方案。
输入
由文件hanoi.in给出输入数据。第1 行是给定的正整数n。
输出
将计算出的最优移动方案输出到文件hanoi.out。文件的每一行由一个正整数k和2个字符c1和c2组成,表示将第k个圆盘从塔座c1移到塔座c2上
样例输入
3
样例输出
1 A B
2 A C
1 B C
3 A B
1 C A
2 C B
1 A B
提示
n<10
#include <bits/stdc++.h>
using namespace std;
void hanot(int n,char a,char b, char c){
if(n>0){
hanot(n-1,a,c,b);
cout<<n<<' '<<a<<' '<<b<<endl;
hanot(n-1,c,b,a);
}
}
int main(){
int n;
cin>>n;
hanot(n,'A','B','C');
return 0;
}