大数加减法(洛谷的P1601、P2142)

本文详细介绍了如何使用字符串和数组处理大数加法和减法,包括处理进位、借位和输出结果等关键步骤。

大数加法:
原题连接
对于一些范围比较小的数据,利用C/C++自带的数据类型就可以解决。但是对于一些数据比如10^1000000这样的数据,我们如何处理呢?
这时,我们就要用到大数运算了。
大数运算的根本在于要用字符串或是数组对每一位进行保存。下面介绍一下大数加法。由于大数加法比较简单,我们直接对字符串进行操作,不在用数组了。
第一步是以字符串的形式输入两个整数

 string a, b;
    cin >> a >> b;
    string resa = a;
    string resb = b;
    for (int i = 0; i < a.size(); i++)
        resa[i] = a[a.size() - 1 - i];
    for (int i = 0; i < b.size(); i++)
        resb[i] = b[b.size() - 1 - i];
    int maxSize = a.size() > b.size() ? a.size() : b.size();

resa,resb是a,b的反转字符串。为什么反转?我们模拟一下我们做加法,是列一个竖式从个位加到最高位。所以我们反转一下字符串便于运算。

  string ans;
    int i = 0, j = 0;
    bool flag = 0;
    while (resa[i] != '\0'|| resb[j] != '\0') {
        if (resa[i] != '\0' && resb[j] != '\0') {
            int x = resa[i] + resb[j] - '0' - '0' + flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            i++;
            j++;
        }

这里有几个变量ans是答案,flag是进位(因为进位不可能为2,所以我们直接用bool变量),因为可能存在要进位的情况。接下来进入循环。循环的终止条件是什么呢?就是两个字符串都加到最高位了,也就是此时为’\0’状态。那么我们考虑一下可能存在的情况。第一种情况:两个字符串都没有到达最高位。int x = resa[i] + resb[j] - ‘0’ - ‘0’ + flag这条语句就是就是计算此时该位相加的结果,注意要减去’0’,而且要加上进位的结果。如果x>=10说明要进位了,我们在ans后添加x的各位数字(要加上’0’),并把flag赋值为1,代表要进位;否则就直接把x添加上去,flag赋值为。然后i++,j++,移动至下一个字符。

else if (resa[i] != '\0' && resb[j] == '\0') {
            int x = resa[i] - '0'+ flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            i++;
        }
        else {
            int x = resb[j] - '0' + flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            j++;
        }

我们想,加法会有两个数位数不一致的情况。那么还需要处理一下这种情况。但其实实质与两位相加相同。这可以理解为其中一位为零。

 if (flag)
        ans.push_back('1');
    for (int i = ans.size() - 1; i >= 0; i--)
        cout << ans[i];

当然还有一种情况,举个栗子,50+50,最后肯定要再添一位。但是在循环中有进位有延后。所以我们还要再判断一下是否要进位。最后逆序输出。
完整代码:

#include<iostream>
#include<string>
using namespace std;
int main()
{
    string a, b;
    cin >> a >> b;
    string resa = a;
    string resb = b;
    for (int i = 0; i < a.size(); i++)
        resa[i] = a[a.size() - 1 - i];
    for (int i = 0; i < b.size(); i++)
        resb[i] = b[b.size() - 1 - i];
    int maxSize = a.size() > b.size() ? a.size() : b.size();
    string ans;
    int i = 0, j = 0;
    bool flag = 0;
    while (resa[i] != '\0'|| resb[j] != '\0') {
        if (resa[i] != '\0' && resb[j] != '\0') {
            int x = resa[i] + resb[j] - '0' - '0' + flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            i++;
            j++;
        }
        else if (resa[i] != '\0' && resb[j] == '\0') {
            int x = resa[i] - '0'+ flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            i++;
        }
        else {
            int x = resb[j] - '0' + flag;
            if (x >= 10) {
                ans.push_back(x % 10 + '0');
                flag = 1;
            }
            else {
                ans.push_back(x + '0');
                flag = 0;
            }
            j++;
        }
    }
    if (flag)
        ans.push_back('1');
    for (int i = ans.size() - 1; i >= 0; i--)
        cout << ans[i];
    return 0;
}

大数减法:
原题链接
大数减法与之类似,但略微复杂一些,这里用数组会好处理一些。

const int MAX = 100000;
int main()
{
 int a_num[MAX] = { 0 }, b_num[MAX] = { 0 };
 string a, b;
 cin >> a >> b;
 int alen = a.size();
 int blen = b.size();
 if (alen < blen || alen == blen && a < b) {
  swap(a, b);
  swap(alen, blen);
  cout << "-";
 }
 for (int i = 0; i < alen; i++) {
  a_num[alen - i] = a[i] - '0';
 }
 for (int i = 0; i < blen; i++) {
  b_num[blen - i] = b[i] - '0';
 }

与大数加法类似,我们先以字符串形式输入数据。我们要用a_num这个数组储存答案,我们就要判定一下是否要把a,b交换。为什么呢?举个栗子,计算15-20,我们是用20-15再添负号的。所以这就要求a要大于b。a大于b的条件是a的长度小于b,或是长度一样但是a的字典序大于b。当a小于b时,我们就要交换a,b。同时由于a<b,我们要在输出一个负号。然后把a的逆序赋给a_num数组。在这之中,a_num[1]储存的是个位数字。b同理。

for (int i = 1; i <= alen; i++) {
  if (a_num[i] < b_num[i]) {
   a_num[i] += 10;
   a_num[i] -= b_num[i];
   a_num[i + 1] -= 1;
  }
  else
   a_num[i] -= b_num[i];
 }

然后我们开始逐位处理,如果a_num[i]<b_num[i],我们就需要借位,直接在该位加十,同时下一位减一。否则直接相减就可。

 while (a_num[alen] == 0 && alen > 1)
  alen--;
 for (; alen >= 1; alen--)
  cout << a_num[alen];
 return 0;

最后输出,但是相减可会导致高位为0,所以要去除所有的0,最后逆序输出即可。
完整代码:

#include<iostream>
#include<string>
using namespace std;
const int MAX = 100000;
int main()
{
	int a_num[MAX] = { 0 }, b_num[MAX] = { 0 };
	string a, b;
	cin >> a >> b;
	int alen = a.size();
	int blen = b.size();
	if (alen < blen || alen == blen && a < b) {
		swap(a, b);
		swap(alen, blen);
		cout << "-";
	}
	for (int i = 0; i < alen; i++) {
		a_num[alen - i] = a[i] - '0';
	}
	for (int i = 0; i < blen; i++) {
		b_num[blen - i] = b[i] - '0';
	}
	for (int i = 1; i <= alen; i++) {
		if (a_num[i] < b_num[i]) {
			a_num[i] += 10;
			a_num[i] -= b_num[i];
			a_num[i + 1] -= 1;
		}
		else
			a_num[i] -= b_num[i];
	}
	while (a_num[alen] == 0 && alen > 1)
		alen--;
	for (; alen >= 1; alen--)
		cout << a_num[alen];
	return 0;

}
<think>好的,我需要帮助用户查找洛谷P1601的题解或相关信息。首先,用户提供的引用中有提到引用[3]是关于P1601、P1303和P1009的高精度题目,特别是A+B Problem。因此,我应该重点参考引用[3]的内容。 接下来,我需要确认题目P1601的具体要求。根据引用[3],题目涉及高精度运算,输入的两个数a和b不超过10的500次方,说明需要处理大数相加的问题,普通的整型变量无法存储这么大的数值,必须用字符串处理每一位数字。 然后,我需要解析用户提供的引用内容。引用[3]提到分两行输入,输出格式需要正确的结果,这意味着在编程实现时需要注意输入输出的处理方式。此外,引用[3]还提到了高精度的算法,这通常涉及到逐位相加并处理进位的问题。 接下来,我需要整理解题思路。高精度加法的基本步骤是将两个字符串形式的数字逆序,逐位相加,处理进位,最后将结果逆序输出。需要特别注意前导零的情况,以及最高位的进位处理。 然后,我需要编写示例代码。根据常见的C++高精度加法实现方法,可以写出相应的函数。代码需要包括输入处理、字符串逆序、逐位相加、进位处理和结果逆序输出等步骤。 最后,我需要生成相关问题,这些问题应该围绕高精度算法、洛谷平台的使用以及其他相关题目展开,帮助用户进一步学习。</think>### 洛谷 P1601 高精度加法解析 洛谷 P1601 是典型的高精度加法题目,要求处理长度不超过 $10^{500}$ 的非负整数相加[^3]。由于常规数据类型无法存储如此大的数值,需通过字符串逐位运算实现。 #### 解题步骤 1. **输入处理** 读取两行字符串 $a$ 和 $b$,如: ```plaintext 1145141919810 2000000000001 ``` 2. **逆序对齐** 将字符串反转,使个位对齐: $$a_{rev} = "019181945411" \quad b_{rev} = "1000000000002"$$ 3. **逐位相加** 从低位到高位依次相加,记录进位: ```python carry = 0 for i in range(max_len): digit_a = int(a_rev[i]) if i < len_a else 0 digit_b = int(b_rev[i]) if i < len_b else 0 total = digit_a + digit_b + carry result.append(total % 10) carry = total // 10 ``` 4. **处理最高位进位** 若循环结束后 $carry > 0$,需补上最高位: $$3145141919811$$ #### 示例代码(C++) ```cpp #include <iostream> #include <algorithm> using namespace std; string add(string a, string b) { reverse(a.begin(), a.end()); reverse(b.begin(), b.end()); string res; int carry = 0; for (int i = 0; i < max(a.size(), b.size()); ++i) { int na = (i < a.size()) ? (a[i] - '0') : 0; int nb = (i < b.size()) ? (b[i] - '0') : 0; int sum = na + nb + carry; res.push_back(sum % 10 + '0'); carry = sum / 10; } if (carry) res.push_back('1'); reverse(res.begin(), res.end()); return res; } int main() { string a, b; cin >> a >> b; cout << add(a, b); return 0; } ``` #### 注意事项 - **前导零处理**:输入可能含前导零,但题目未明确要求处理,可保留原始格式 - **时间复杂度**:$O(n)$ 时间复杂度,$n$ 为数字长度
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值