介绍一下很可怕但是用处很大的高精度算法叭
两天才学会的可怕算法
基本思路就是用字符串来输入大数
然后把每一位转换成数字进行运算
这样的话两个大数每一位之间的运算就不会爆long long
高精度加法
分析:
高精度加法
将两个大数用字符串输入,前补0弄成长度相同的两个字符串,然后每一位对应相加,定义一个x来记录进位,上一位的和大于9,就用x记录下来进位,加到下一位上即可
/**
高精度加法
**/
//以字符串输出
string s1,s2;
string add(string s1,string s2)
{
string s;
int len1 = s1.length();
int len2 = s2.length();
//前面补0,弄成长度相同
if(len1 < len2)
{
for(int i=1;i<=len2-len1;i++)
s1 = "0"+s1;
}
else
{
for(int i=1;i<=len1-len2;i++)
s2 = "0"+s2;
}
len1 = s1.length();
int x = 0;//进位
int temp;//余数
for(int i=len1-1;i>=0;i--)
{
temp = s1[i]-'0' + s2[i]-'0' + x;//相加并且加上上一位的进位
x = temp/10;//计算这一位的进位
temp %= 10;//保留余数
s = char(temp+'0')+s;//加进字符串中
}
if(x != 0) s = char(x+'0')+s;//加上最后一位的进位
return s;
}
int main()
{
cin >> s1 >> s2;
cout << add(s1,s2) << endl;
return 0;
}
//以数组输出
string s1,s2;
int a[maxn],b[maxn],c[maxn];
int alen,blen,len;
int main()
{
cin >> s1 >> s2;
memset(c,0,sizeof(c));
alen = s1.size();
blen = s2.size();
for(int i=1;i<=alen;i++) a[i] = s1[alen-i]-'0';
for(int i=1;i<=blen;i++) b[i] = s2[blen-i]-'0';
int x = 0;//进位
if(alen < blen) swap(alen,blen);
for(int i=1;i<=alen+1;i++)
{
c[i] = a[i]+b[i]+x;
x = c[i]/10;
c[i] %= 10;
}
len = alen+1;
while(c[len] == 0 && len > 1) len--;
for(int i=len;i>=1;i--)
printf("%d",c[i]);
printf("\n");
return 0;
}
高精度减法
分析:
和之前高精度加法的基本思想相同,只是需要注意,减法要大数减小数,所以要提前比较两个的数大小。每一位对应相减,不够减的话,就借位,即这一位+10,下一位-1,之后再进行减法运算,还要注意0和负数的情况
/**
高精度减法
**/
const int maxn = 5e3 + 7;
int a[maxn],b[maxn],c[maxn];
string s,ss;
bool f = 0;//记录结果为正还是为负
bool compare(int alen,int blen)
//比较一下两个串的大小,只能大数减小数
{
if(alen < blen) return true;
if(alen == blen) return s < ss;
return false;
}
int main()
{
cin >> s >> ss;
int alen = s.size();
int blen = ss.size();
if(compare(alen,blen))
{
swap(s,ss);
f = 1;
}
alen = s.size();
blen = ss.size();
for(int i=1;i<=alen;i++) a[i] = s[alen-i]-'0';
for(int i=1;i<=blen;i++) b[i] = ss[blen-i]-'0';
//转换成数字存入数组中
for(int i=1;i<=alen;i++)
{
if(a[i] < b[i])//这一位数字不够减
{
a[i+1]--;//借位,后一位-1,这一位+10
a[i] += 10;
}
c[i] = a[i]-b[i];//相减
}
int len = alen;
while(len >= 1 && c[len] == 0) len--;//去掉前导零
if(len < 1) printf("0");
//如果最后长度小于1,说明结果为0,直接输出0
if(f) printf("-");
//如果进行交换,说明被减数小于减数,输出负号
for(int i=len;i>=1;i--)
printf("%d",c[i]);
printf("\n");
return 0;
}
高精度乘法
分析:
将两个大数用字符串表示,输入字符串,将每个字符按逆序转化成数字存放到数组中,然后按照竖式计算的方法,错位相加得到数组c的每一项,然后进行进位运算,最后逆序输出
/**
高精度乘法
**/
char a1[10001],b1[10001];
int a[10001],b[10001],c[10001];
int len,alen,blen;
int main ()
{
cin >> a1 >> b1;
int alen = strlen(a1);
int blen = strlen(b1);
for(int i=1;i<=alen;i++) a[i] = a1[alen-i]-'0';
for(int i=1;i<=blen;i++) b[i] = b1[blen-i]-'0';
for(int i=1;i<=blen;i++)
for(int j=1;j<=alen;j++)
c[i+j-1] += a[j]*b[i];
//c数组存储好了没有进位之前的
for(int i=1;i<alen+blen;i++)
{
if(c[i] > 9)//大于9就需要进位
{
c[i+1] += c[i]/10;//给下一位加上进位的数
c[i] %= 10;//这一位保留余数
}
}
len = alen+blen;
while(c[len] == 0 && len > 1)
len--;//去掉前导零
for(int i=len;i>=1;i--)
printf("%d",c[i]);
printf("\n");
return 0;
}
高精度阶乘
分析:
同样的,用一个数组来记录每次相乘后没有进位的乘积,定义一个x来表示每次进位的数字,定义一个p来记录每次相乘得出的数字位数,降低复杂度
因为这个地方我直接用maxn结果超时了
于是就用了一个p来记录数字位数
求N!的值(ni)
题目描述
用递归算法,求N!的精确值(N以一般整数输入)。
输入
10
输出
10!=3628800
样例输入 Copy
10
样例输出 Copy
10!=3628800
/**
高精度阶乘
**/
int c[maxn];
int main()
{
int n,p; cin >> n;
memset(c,0,sizeof(c));
c[0] = 1;
p = 1;//用来记录数字位数
for(int i=2; i<=n; i++)
{
int x = 0;//表示进位
for(int j=0; j<p; j++)
{
c[j] = c[j]*i+x;//这一位+进位
x = c[j]/10;//判断并存储本次的进位情况
c[j] %= 10;//保留进位后的余数
}
while(x > 0)
{
c[p] = x % 10;
x /= 10;
p++;
}
}
int j;
for(j=maxn-1;j>=0;j--)
if(c[j]) break;//去掉前导零
printf("%d!=",n);
for(int i=j;i>=0;i--)
printf("%d",c[i]);
printf("\n");
return 0;
}
/**
这个题相对于其他高精度题目来说相对简单一点
因为n给出范围n <= 50
所以输入时不需要用字符串进行切换
用数组记录每一位上的数字即可
**/
int a[2000],b[2000],c[2000];
int sum[2000];
void pplus(int *a,int *c)
{
int x = 0;
for(int i=1;i<=1000;i++)
{
c[i] += a[i]+x;
x = c[i]/10;
c[i] %= 10;
}
}
void cheng(int *a,int c)
{
int x = 0;
for(int i=1;i<=1000;i++)
{
a[i] = a[i]*c+x;
x = a[i]/10;
a[i] %= 10;
}
}
int main()
{
int n; cin >> n;
a[1] = 1;
for(int i=1;i<=n;i++)
{
cheng(a,i);//先求i的阶乘放进数组a
pplus(a,c);//求一次阶乘加和一次,把每一位放进数组c
}
bool flag = 0;
for(int i=1000;i>=1;i--)
{
if(c[i] != 0) flag=1;
if(flag) cout << c[i];
}
return 0;
}
高精度除法
高精除低精分析:
按位相除保留余数用到下一位的除法上即可
char str[100];
int a[100],b,c[100];
int alen,len;
int main()
{
memset(a,0,sizeof(a));
memset(c,0,sizeof(c));
cin >> str;
cin >> b;
int x = 0;
alen = strlen(str);
for(int i=0; i<alen; i++) a[i+1] = str[i]-'0';
for(int i=1; i<=alen; i++)//按位相除
{
c[i] = (x*10+a[i])/b;
x = (x*10+a[i])%b;
}
len = 1;
while(c[len] == 0 && len < alen) len++;
for(int i=len; i<=alen; i++)
printf("%d",c[i]);
printf("\n");
return 0;
}