新手自学,结合蓝桥杯oj, leetcode, 洛谷, oj备用等网站题目,详细介绍我对这一算法的学习过程
目录
一,解释,题目和代码
1,P1601 A+B Problem(高精)
代码
二,其他相关题目
2,P1591阶乘数码
代码
3,P1045 [NOIP2003 普及组] 麦森数(未遂)
编辑
代码(未遂)
总结
前言:
当我们需要求两个很大的数相加,比如10^450 + 10^436或阶乘和,用long long已经满足不了
这时就需要将两个数字按字符串输入,转化为整型后存入数组。
存入后如何实现相加呢,这就需要数组进位了。下面将详细介绍数组进位的算法:
数组进位:
原理与小学一年级学的竖式加法类似,比如193 + 218 = ?
先加个位3 + 8 = 11,为了使数组中每个元素都为个位数(以实现后续相加),我们需要11 / 10 = 1给下一位进个1,并在本位保留11 % 10 = 1,是不是和进制转换很像呢
这就是数组进位的原理
下面请看题目和代码:
题目:
题目描述
高精度加法,相当于 a+b problem,不用考虑负数。
输入格式
分两行输入,a,b <= 10^500
输出格式
输出只有一行,代表 a+b 的值
输入
1
1
输出
2
输入
1001
9099
输出
10100
#include
using namespace std;
const int N = 510;
int a[N], b[N], c[N];
int main()
{
int i;
string str1, str2;
cin>>str1>>str2;
//第一步:将字符串转换成整型输入到数组中
for(i = 0; i < str1.size(); ++i)//.size()求string类字符串长度,strlen()求字符数组字符串长度
a[i] = str1[str1.size() - i - 1] - '0';//比如str1为158, str1[3 - 0 - 1]就是str1[2] = 8, 为最小位
for(i = 0; i < str2.size(); ++i)//也就是将字符串最后一位输入到数组第一位
b[i] = str2[str2.size() - i - 1] - '0';
//第二步:高精度加法,即数组进位
int len = max(str1.size(), str2.size());
for(i = 0; i < len; ++i)
{
c[i] = c[i] + a[i] + b[i];
c[i + 1] = c[i] / 10;//保留进位
c[i] = c[i] % 10;//保留个位
}
//第三步:完善细节
len += 1;//防止出现996 + 111 = 107而不是1107最大位漏了的情况
if(c[len - 1] == 0)//如果c的最大位为0,说明len + 1后多进了一位0
len -= 1;//防止出现123 + 789 = 0912多了一位0的情况
//第四步:逆序输出数组c(也就是从大到小)
for(i = len - 1; i >= 0; --i)
cout<
题目来源: P1601 A+B Problem(高精) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
代码在洛谷可Accepted,原题在网址里,需要练习的可自行提交看是否通过
下面我提供几组测试数据,上洛谷前可先行检测
789
1
790
996
111
1107
123
789
912
999888777666555444333222111
111222333444555666777888999
1111111111111111111111111110
我会罗列出网址,代码,输入输出和解析
代码会是高精度加法的不同表现方法
题目
求 n! 中某个数码出现的次数
输入格式
第一行为 t (t <= 10),表示数据组数。接下来 t 行,每行一个正整数 n (n <= 1000) 和数码 a
输出格式
对于每组数据,输出一个整数,表示 n! 中 a 出现的次数
输入
2
5 2
7 0
输出
1
2
#include
#include//scanf()
#include//memset(数组名, 0, sizeof(数组名))
using namespace std;
int m[10000];
int main()
{
int i, j, t;
cin>>t;//将输入t组数据
int c = 0;//保留进位
int sum = 0;//中间值, c, sum在for内初始化会累加
for(int k = 0; k < t; ++k)//这里不要声明i, 会被下面的i干扰
{
memset(m,0,sizeof(m));//对数组m初始化,防止连续输入后累加
int n, a;
scanf("%d %d", &n, &a);//n表示n的阶乘
m[0] = 1;
//↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓核心代码↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
for(i = 2; i <= n; ++i)
for(j = 0; j < 3000; ++j)
{
sum = c + m[j] * i;
m[j] = sum % 10;//保留个位数
c = sum / 10;//保留进位
}
//↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑核心代码↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑
long long num = 0;//a出现的次数
for(i = 3000; i >=0; --i)
if(m[i] != 0)//数据开始出现
{
for(j = i; j >= 0; --j)
if(m[j] == a)
num++;
break;//从a最后一个数输出到a[0]
}
cout<
输入输出
6
12 3
0
12 7
1
104 5
14
104 3
12
104 0
33
10 0
2
分析
中间还出现一个报错:invalid types ‘int[int]’ for...意思是数组名与常量名重复定义,毕竟数组习惯用a[10000]了
耗时198ms
一开始用了1.26秒,因为22行j < 10000,多了不必要的循环,当改成j <= 3000,就405ms,开启O2优化直接198ms
题目来源:P1591 阶乘数码 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
需要的可在洛谷自行练习提交
害,突然发现这个要高精度乘法,还没学,想了两个小时没ACCEPTED
题目
注意,代码没过,只是我一开始的思路,等系统学完高精度加,减,乘,除,我再补充完整
#include
#include//memset()
using namespace std;
int a[100010];
int main()
{
memset(a, 0, sizeof(a));//初始化数组是好习惯
a[0] = 2;
int p, i, j;//2^p
cin>>p;
int c = 0;//c为进位
/*↓↓↓↓↓↓↓↓↓↓↓↓↓↓核心代码↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓*/
for(i = 1; i < p; ++i) {
j = 0;
while(j < 500) {
a[j] = a[j] + ;
if(a[j] >= 10) {
a[j + 1] = a[j] / 10;//保留进位
a[j] = a[j] % 10;//保留个位数
j++;
}
}
}
/*↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑核心代码↑↑↑↑↑↑↑↑↑↑↑↑↑↑*/
for(int k = 499; k >= 1; --k) {
cout<
这个代码没过
题目来源:P1045 [NOIP2003 普及组] 麦森数 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
为了2023-4月蓝桥杯A组拿个省二,我还要学习的有:
1,排序(选择,插入,冒泡,快速的手写), sort()
2,枚举(循环遍历,dfs,bfs)(暴力出奇迹)
3,最大公约数,最小公倍数,素数筛
4,二分查找,差分查找,dfs剪枝优化
5,递归(dfs, 阶乘),分治(手写快排)
6,贪心算法
7,队列,栈,线性表,图
8,动态规划
实施步骤:
1,学完MOOC中C++指针,结构体链表,面向对象的内容,做3~5道编程题
2,挑拣着做下洛谷入门题单,巩固下输入输出以及基本语法
3,对照1~8,逐个击破
分配时间:
寒假每日3小时,开学后每日2小时
长路漫漫,共勉,A组省三都不好拿我觉得,本来就0基础