今天我要开启一个新计划----【C++天梯计划】
目的是通过天梯计划,通过题目和知识点串联的方式,完成C++复习与巩固。
高精度算法(High Accuracy Algorithm)是处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除,乘方,阶乘,开方等运算。对于非常庞大的数字无法在计算机中正常存储,于是,将这个数字拆开,拆成一位一位的,或者是四位四位的存储到一个数组中, 用一个数组去表示一个数字,这样这个数字就被称为是高精度数。高精度算法就是能处理高精度数各种运算的算法,但又因其特殊性,故从普通数的算法中分离,自成一家。
#include
#include
#include
using namespace std;
struct Wint:vector<int>//用标准库vector做基类,完美解决位数问题,同时更易于实现
{
//将低精度转高精度的初始化,可以自动被编译器调用
//因此无需单独写高精度数和低精度数的运算函数,十分方便
Wint(int n=0)//默认初始化为0,但0的保存形式为空
{
push_back(n);
check();
}
Wint& check()//在各类运算中经常用到的进位小函数,不妨内置
{
while(!empty()&&!back())pop_back();//去除最高位可能存在的0
if(empty())return *this;
for(int i=1; i<size(); ++i)
{
(*this)[i]+=(*this)[i-1]/10;
(*this)[i-1]%=10;
}
while(back()>=10)
{
push_back(back()/10);
(*this)[size()-2]%=10;
}
return *this;//为使用方便,将进位后的自身返回引用
}
};
//输入输出
istream& operator>>(istream &is,Wint &n)
{
string s;
is>>s;
n.clear();
for(int i=s.size()-1; i>=0; --i)n.push_back(s[i]-'0');
return is;
}
ostream& operator<<(ostream &os,const Wint &n)
{
if(n.empty())os<<0;
for(int i=n.size()-1; i>=0; --i)os<<n[i];
return os;
}
//比较,只需要写两个,其他的直接代入即可
//常量引用当参数,避免拷贝更高效
bool operator!=(const Wint &a,const Wint &b)
{
if(a.size()!=b.size())return 1;
for(int i=a.size()-1; i>=0; --i)
if(a[i]!=b[i])return 1;
return 0;
}
bool operator==(const Wint &a,const Wint &b)
{
return !(a!=b);
}
bool operator<(const Wint &a,const Wint &b)
{
if(a.size()!=b.size())return a.size()<b.size();
for(int i=a.size()-1; i>=0; --i)
if(a[i]!=b[i])return a[i]<b[i];
return 0;
}
bool operator>(const Wint &a,const Wint &b)
{
return b<a;
}
bool operator<=(const Wint &a,const Wint &b)
{
return !(a>b);
}
bool operator>=(const Wint &a,const Wint &b)
{
return !(a<b);
}
//加法,先实现+=,这样更简洁高效
Wint& operator+=(Wint &a,const Wint &b)
{
if(a.size()<b.size())a.resize(b.size());
for(int i=0; i!=b.size(); ++i)a[i]+=b[i];
return a.check();
}
Wint operator+(Wint a,const Wint &b)
{
return a+=b;
}
//减法,返回差的绝对值,由于后面有交换,故参数不用引用
Wint& operator-=(Wint &a,Wint b)
{
if(a<b)swap(a,b);
for(int i=0; i!=b.size(); a[i]-=b[i],++i)
if(a[i]<b[i])//需要借位
{
int j=i+1;
while(!a[j])++j;
while(j>i)
{
--a[j];
a[--j]+=10;
}
}
return a.check();
}
Wint operator-(Wint a,const Wint &b)
{
return a-=b;
}
//乘法不能先实现*=,原因自己想
Wint operator*(const Wint &a,const Wint &b)
{
Wint n;
n.assign(a.size()+b.size()-1,0);
for(int i=0; i!=a.size(); ++i)
for(int j=0; j!=b.size(); ++j)
n[i+j]+=a[i]*b[j];
return n.check();
}
Wint& operator*=(Wint &a,const Wint &b)
{
return a=a*b;
}
//除法和取模先实现一个带余除法函数
Wint divmod(Wint &a,const Wint &b)
{
Wint ans;
for(int t=a.size()-b.size(); a>=b; --t)
{
Wint d;
d.assign(t+1,0);
d.back()=1;
Wint c=b*d;
while(a>=c)
{
a-=c;
ans+=d;
}
}
return ans;
}
Wint operator/(Wint a,const Wint &b)
{
return divmod(a,b);
}
Wint& operator/=(Wint &a,const Wint &b)
{
return a=a/b;
}
Wint& operator%=(Wint &a,const Wint &b)
{
divmod(a,b);
return a;
}
Wint operator%(Wint a,const Wint &b)
{
return a%=b;
}
//顺手实现一个快速幂,可以看到和普通快速幂几乎无异
Wint pow(const Wint &n,const Wint &k)
{
if(k.empty())return 1;
if(k==2)return n*n;
if(k.front()%2)return n*pow(n,k-1);
return pow(pow(n,k/2),2);
}
//通过重载运算符,还可以实现++、--、^、!、逻辑运算符等很多运算,十分简单,此处都不写了
int main()//你完全可以像int一般便捷地使用Wint,如下
{
Wint a,b;
//可以把b改成int型,仍能正常使用
cin>>a>>b;
cout<<(a<b)<<endl
<<(a==b)<<endl
<<a+b<<endl
<<a-b<<endl
<<a*b<<endl
<<a/b<<endl
<<a%b<<endl
<<pow(a,b);
}
题目描述
求 22 的 nn 次方。( 0 \le n \le 1000≤n≤100)
输入
从键盘读入一个整数 nn;
输出
请输出 22 的 nn 次方;
样例
输入
100
输出
1267650600228229401496703205376思路
准备一个整数数组 aa ,存放 22 的 nn 次方, aa 数组默认存储一个 11 ,代表 22 的 00 次方! 循环 nn 次,每次循环都要将 aa 数组的每一位 \times 2×2 ,并进位,然后判断 aa 数组 \times 2×2 后是否多出一位,如果多出一位, aa 数组位数计数器 k++k++。
逆序输出 aa 数组的 kk 个数。
#include
using namespace std;
int a[100] = {1};
//k代表a数组元素的个数,代表了高精度的整数的位数
int i,j,k = 1,n;
int main(){
cin>>n;
//循环n次,每次都将a数组 * 2
for(i = 1;i <= n;i++){
//将a数组的每一位都 * 2
for(j = 0;j < k;j++){
a[j] = a[j] * 2;
}
//逐位进位
for(j = 0;j < k;j++){
if(a[j] >= 10){
a[j+1]=a[j+1]+a[j]/10;
a[j]=a[j]%10;
}
}
//判断a数组是否多出一位
if(a[k] != 0){
k++;
}
}
//逆序输出a数组的k个数
for(i = k - 1;i >= 0;i--){
cout<<a[i];
}
}
题目描述
我军拦截敌军传递了2个数字串,后经侦查得知,这两个数字串中包含了一个很重要的密码,这个密码的破译方式为,用这两个数字串中的大数 – 小数,得到结果后将结果转换为16进制(转换时如需使用字母请使用大写字母),就是敌军想要传递的密码。
比如,敌军传递了下列两个数字串:
99999999999999999999999999999999999999973
99999999999999999999999999999999999999999
大数 – 小数的差值 = 26,转换为16进制的结果为1A,也就是1A就是敌军想要传递的密码。
请编程实现破译密码的过程。输入
输入有2行,分别是2个不超过200位的整数(2个数不存在前导0,也就是不会读入类似00123这样的数),且已知2个整数的差是一个不超过18位的整数。
输出
输出按题意计算出的16进制数。
样例
输入
99999999999999999999999999999999999999973
99999999999999999999999999999999999999999
输出
1A
输入
999999999
3847
输出
3B9ABAF8思路
1.判断如果s1对应的数字比s2小,交换
2.高精减,得到结果
3.将结果计算为10进制的long long
4.将该整数转换为16进制
#include
using namespace std;
string s1,s2;
long long x,t = 1;//t表示10的次方
int a[210],b[210],c[210];
string r,t2 = "0123456789ABCDEF";
int main(){
cin>>s1>>s2;
//1.判断大小
if(s1.size()<s2.size()||(s1.size()==s2.size()&&s1<s2)){
swap(s1,s2);
}
//2.逆序存储
for(int i = 0;i < s1.size();i++){
a[i] = s1[s1.size()-i-1] - '0';
}
for(int i = 0;i < s2.size();i++){
b[i] = s2[s2.size()-i-1] - '0';
}
//3.逐位相减
int len = max(s1.size(),s2.size());
for(int i = 0;i < len;i++){<br />
if(a[i] < b[i]){
a[i+1]--;
a[i]=a[i]+10;
}
c[i] = a[i] - b[i];
}
//4.从下标为0的位置向后计算到倒过来的第1个非0位置
//将结果转换为long long
int p = 0;
for(int i = len - 1;i >= 0;i--){
if(c[i] != 0){
p = i;
break;
}
}
for(int i = 0;i <= p;i++){
x = x + c[i] t;
t = t 10;
}
//cout<
//将x转16进制
if(x == 0){
cout<<0;
return 0;
}
while(x != 0){
r = t2[x%16]+r;
x = x / 16;
}
cout<<r;
return 0;
}