目录
高精度加法:
高精度减法:
高精度乘法:高精度最简单的运算了吧。
高精度除法:高精度算法中最难理解的算法。
高精度取余:高精度中代码最短的算法。
高精度算法例题:
HDU 1002 A - A + B Problem II
HDU1047 Integer Inquiry
HDU 1250 Hat's Fibonacci
HDU - 1865 1sting
高精度算法,说白了其实就是用程序手动模拟我们在草稿本上的运算。
1.概念
高精度使用数组来存储整数,模拟手算进行四则运算
2.高精度运算涉及到的问题
(1) 数据的输入:因为数字很大,不能用整数来输入,所以只能用字符数组输入,然后转化。
scanf("%s %s",str,str1);
(2) 数据的存储:因为后面的运算是从前向后进行,所以我们在转化的时候需要反向来转化;
int l1=strlen(str),l2=strlen(str1);
for(int i=0;i
(3)数据的运算:进位和借位,这里就是代码的核心了,就是手动模拟人算的。
int l=1,x=0;//x是处理进位
while(l<=l1||l<=l2)
{
c[l]=a[l]+b[l]+x;
x=c[l]/10;//超过10要进位
c[l]%=10;//进位后留下来的数
l++;
}
c[l]=x;//最后一位可能会进位。
(4)结果的输出:小数点的位置和处于多余的0:最后一步很简单,看代码就能懂
while(c[l]==0&&l>=0)//处理前置0
l--;
if(l==-1)//结果为0
printf("0");
else
for(;l>0;l--)
printf("%d",c[l]);
printf("\n");
整体代码:
#include
#include
#include
const int maxn=1e5+10;
const int mod=1e9+7;
const int inf=1e8;
#define me(a,b) memset(a,b,sizeof(a))
using namespace std;
int main()
{
char str[maxn],str1[maxn];
int a[maxn],b[maxn],c[maxn];
me(a,0),me(b,0),me(c,0);
scanf("%s%s",str,str1);
int l1=strlen(str),l2=strlen(str1);
for(int i=0; i=0)//处理前置0
l--;
if(l==-1)//结果为0
printf("0");
else
for(; l>0; l--)
printf("%d",c[l]);
printf("\n");
return 0;
}
Java代码:
import java.math.BigInteger;
import java.util.Scanner;
public class mian {
private static Scanner cin;
public static void main(String[] args) {
cin=new Scanner(System.in);
while(cin.hasNext()) {
BigInteger a,b,sum;
a=cin.nextBigInteger();
b=cin.nextBigInteger();
sum=a.add(b);
System.out.println(sum);
}
}
}
和高精度加法相比,减法在差为负数时处理的细节更多一点:当被减数小于减数时,差为负数,差的绝对值是减数减去被减数;在程序实现上用一个变量来存储符号位,用另一个数组存差的绝对值。
算法流程:
(1)读入被减数S1,S2(字符串):和高精度加法一样,可以参考上面的那个
(2)置符号位:判断被减数是否大于减数:大则将符号位置为空;小则将符号位置为“-”,交换减数与被减数;
int l1=strlen(str1),l2=strlen(str2);
if(l1==l2&&strcmp(str1,str2)<0)//减数比被减数大
jianfa(str2,str1,1);
else if(l1
(3)被减数与减数处理成数值,放在数组中;
int len1=strlen(str1),len2=strlen(str2);
for(int i=0,j=len1-1; i
(4)运算:
A、取数;
B、判断是否需要借位;
C、减,将运算结果放到差数组相应位中;
D、判断是否运算完成:是,转5;不是,转A;
while(l<=len1)
{
c[l]=a[l]-b[l];
if(c[l]<0)
{
c[l]+=10;
a[l+1]--;
}
l++;
}
(5)打印结果:符号位,第1位,循环处理第2到最后一位;
while(c[l]==0&&l>=0)//除去前置0
l--;
if(l==-1)
printf("0");
else
{
if(flog)///减数比被减数大,答案为负数
printf("-");
for(int i=l; i>=0; i--)
printf("%d",c[i]);
}
printf("\n");
整体代码:
#include
#include
#include
#include
#include
Java代码:
import java.math.BigInteger;
import java.util.Scanner;
public class mian {
private static Scanner cin;
public static void main(String[] args) {
cin=new Scanner(System.in);
while(cin.hasNext()) {
BigInteger a,b,sum;
a=cin.nextBigInteger();
b=cin.nextBigInteger();
sum=a.subtract(b);
System.out.println(sum);
}
}
}
既然是一个很大的整数,我们便不能够再用简单的数据类型直接储存这些整数。我们可以自然得想到要通过数组或字符串来储存数字。字符串的特点方便我们对于高位整数的输入,而整形数组的简便性更有利于每个位数的计算,因而我们结合两者的优点,不难得出高精度乘法的大致流程:
a、通过两个字符串输入两个整数;
char str1[maxn], str2[maxn];
scanf("%s%s", str1, str2);
b、引人两个数组,将两个整数通过一定的运算,分别将每一位的数字储存进数组中;
int n = strlen(str1), m = strlen(str2);
int a[maxn], b[maxn],c[maxn];
for (int i = 0, j = n - 1; i < n; i++, j--)
a[i] = str1[j] - '0';
for (int i = 0, j = m - 1; i < m; i++, j--)
b[i] = str2[j] - '0';
c、进行每一位的运算;
我们再声明一个数组c来储存答案。大家通过一个简单的乘法运算进行模拟就可以看出,以同样的储存规则,a[0] * b[0] = c[0]; a[0] * b[1] + a[1] * b[0] = c[1];逐渐我们可以发现规律: "c[i + j] += a[i] * b[j]"同过一个循环去实现,就可以把c[i + j]计算出来,需要指出的是,这里的计算我们还没有进行进位处理。
1 2 3
* 5 6 7
*--------------------------
7 14 21
6 12 18
5 10 15
*--------------------------
5 16 34 32 21
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
c[i + j] += a[i] * b[j];
d、处理进位;
for (int i = 0; i < n + m; i++)
if (c[i] >= 10)
{
c[i + 1] += c[i] / 10;
c[i] %= 10;
}
e、输出结果;
int l=maxn-1;
while(!c[l])
l--;
for (int i = l; i >= 0; i--)
printf("%d", c[i]);
printf("\n");
整体代码:
#include
#include
#include
#include
#include
Java代码:
import java.math.BigInteger;
import java.util.Scanner;
public class mian {
private static Scanner cin;
public static void main(String[] args) {
cin=new Scanner(System.in);
while(cin.hasNext()) {
BigInteger a,b,sum;
a=cin.nextBigInteger();
b=cin.nextBigInteger();
sum=a.multiply(b);
System.out.println(sum);
}
}
}
大数除法,应该算是四则运算里面最难的一种了。不同于一般的模拟,除法操作步数模仿手工除法,而是利用减法操作实现的。
其基本思想是反复做除法,看从被除数里面最多能减去多少个除数,商就是多少。
逐个减显然太慢,要判断一次最多能减少多少个整的10的n次方。
以7546除23为例。
先减去23的100倍,就是2300,可以减3次,余下646。 此时商就是300;
然后646减去23的10倍,就是230,可以减2次,余下186。此时商就是320;
然后186减去23,可以减8次,此时商就是328.
a、通过两个字符串输入两个整数;
scanf("%s %s", str1, str2);
int l1 = strlen(str1), l2 = strlen(str2);///获得大数的位数
b、进行每一位的运算;
void SubStract(int len) {
int i = 0;
while (str1[i] == '0')///查找现在减到哪一位了
i++;
int j = i;
for (; i < len; i++)
str1[i] = str1[i] - str2[i] + '0';///分别将每一位的数字储存进数组中
for (i = len - 1; i > j; i--) {
if (str1[i] < '0')///若该位<0,则需要借位
str1[i] += 10, str1[i - 1]--;
}
}
f、输出结果;
int l=maxn-1;
while(!num_c[l])
l--;
for(int i=l; i>=0; i-- )
printf("%d", num_c[i]);
printf("\n");
整体代码:
#include
#include
#include
using namespace std;
const int maxn = 1e3 + 5;
char str1[maxn], str2[maxn];
int a[maxn];
void SubStract(int len) {
int i = 0;
while (str1[i] == '0')///查找现在减到哪一位了
i++;
int j = i;
for (; i < len; i++)
str1[i] = str1[i] - str2[i] + '0';///分别将每一位的数字储存进数组中
for (i = len - 1; i > j; i--) {
if (str1[i] < '0')///若该位<0,则需要借位
str1[i] += 10, str1[i - 1]--;
}
}
int main() {
while (scanf("%s %s", str1, str2) != EOF) {
int l1 = strlen(str1), l2 = strlen(str2);///获得大数的位数
if (l1 < l2 || (l1 == l2 && strcmp(str1, str2) < 0)) {///如果被除数小于除数,结果为0
printf("0\n");
continue;
}
int k = 0;
while (true) {
a[k] = 0;
while (strcmp(str1, str2) >= 0) {
SubStract(l2), a[k]++;///每成功减一次,将商的相应位加1
}
k++;
if (l1 == l2)///减完了 直接跳出
break;
for (int i = l2 - 1; i >= 0; i--)
str2[i + 1] = str2[i];
str2[0] = '0', l2++, str2[l2] = '\0';
}
int i = 0;
while (a[i] == 0)
i++;
for (; i < k; i++)
printf("%d", a[i]);
printf("\n");
}
return 0;
}
Java代码:
import java.math.BigInteger;
import java.util.Scanner;
public class mian {
private static Scanner cin;
public static void main(String[] args) {
cin=new Scanner(System.in);
while(cin.hasNext()) {
BigInteger a,b,sum;
a=cin.nextBigInteger();
b=cin.nextBigInteger();
sum=a.divide(b);
System.out.println(sum);
}
}
}
#include
#include
#include
#include
#include
using namespace std;
const int maxn=1e4;
int main()
{
char str[maxn];
int mod;
scanf("%s%d",str,&mod);
int ans=0;
for(int i=0;i
Java代码:
import java.math.BigInteger;
import java.util.Scanner;
public class mian {
private static Scanner cin;
public static void main(String[] args) {
cin=new Scanner(System.in);
while(cin.hasNext()) {
BigInteger a,b,sum;
a=cin.nextBigInteger();
b=cin.nextBigInteger();
sum=a.remainder(b);
System.out.println(sum);
}
}
}
题解:模板高精度加法。
#include
#include
int main() {
char str1[10000], str2[10000];
int a[10000], b[10000], c[10000];
int t, k = 0;
scanf("%d", &t);
for (int s = 1; s <= t; s++) {
scanf("%s %s", str1, str2);
if (k++)
printf("\n");
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
memset(c, 0, sizeof(c));
int l1 = strlen(str1), l2 = strlen(str2);
for (int i = 0; i < l1; i++)
a[l1 - i] = str1[i] - '0';
for (int i = 0; i < l2; i++)
b[l2 - i] = str2[i] - '0';
int l = 1, x = 0;
while (l <= l1 || l <= l2) {
c[l] = a[l] + b[l] + x;
x = c[l] / 10;
c[l] %= 10;
l++;
}
c[l] = x;
printf("Case %d:\n", s);
printf("%s + %s = ", str1, str2);
while (c[l] == 0 && l > 0)
l--;
if (l == 0)
printf("0");
else
for (; l > 0; l--)
printf("%d", c[l]);
printf("\n");
}
return 0;
}
题意:让你加n个大数,直到输入0为止,主要运用高精度加法。
#include
#include
using namespace std;
char str[100][1000];
int a[100][1000], b[1000];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n = 0;
memset(a, 0, sizeof(a));
memset(b, 0, sizeof(b));
while (scanf("%s", str[++n]) && str[n][0] != '0');
int len, max = 0;
for (int i = 1; i <= n; i++) {
len = strlen(str[i]);
for (int j = 0; j < len; j++)
a[i][len - j] = str[i][j] - '0';
if (len > max)
max = len;
}
int l = 1;
while (l <= max) {
for (int i = 0; i < n; i++)
b[l] += a[i][l];
b[l + 1] += b[l] / 10;
b[l] %= 10;
l++;
}
while (b[l] == 0 && l > 0)
l--;
if (l == 0)
printf("0");
else
for (; l > 0; l--)
printf("%d", b[l]);
printf("\n");
if (t)
printf("\n");
}
return 0;
}
题解:大数加法,但是数组每个位存一个数可能会超时间或超内存,所以使用较大的进制。
#include
int a[8000][300] = {0};
int main() {
for (int i = 1; i < 5; i++)
a[i][1] = 1;
for (int i = 5; i < 8000; i++) {
for (int j = 1; j < 255; j++) {
a[i][j] += a[i - 1][j] + a[i - 2][j] + a[i - 3][j] + a[i - 4][j];
a[i][j + 1] += a[i][j] / 100000000;
a[i][j] %= 100000000;
}
}
int n;
while (scanf("%d", &n) != EOF) {
int l = 255;
while (a[n][l] == 0)
l--;
printf("%d", a[n][l]);//最前面的数不够8位直接输出
for (--l; l > 0; l--)
printf("%08d", a[n][l]); //这里的%08d估计大家都不陌生了吧?就是不够8位的时候左侧使用0补够 。
printf("\n");
}
}
题解:本题总共分两种情况:
(1)当第n个不与n-1个相加,就以1结尾,有f(n-1)种情况。
(2):第n个1加上第n-1个1,就有发(n-2)种情况以2结尾。
#include
#include
int a[205][255] = {0};
int main() {
a[1][1] = 1, a[2][1] = 2;
for (int i = 3; i < 205; i++) {
for (int j = 1; j < 255; j++) {
a[i][j] += a[i - 1][j] + a[i - 2][j];
a[i][j + 1] += a[i][j] / 100000000;
a[i][j] %= 100000000;
}
}
int n;
scanf("%d", &n);
while (n--) {
char str[300];
scanf("%s", str);
int s = strlen(str);
int l = 251;
while (a[s][l] == 0)
l--;
printf("%d", a[s][l]);
for (--l; l > 0; l--)
printf("%08d", a[s][l]);
printf("\n");
}
}