1.%运算
a%b=c
计算机中实现%运算的方法为,先求
∣
a
∣
|a|
∣a∣%
∣
b
∣
|b|
∣b∣得到
c
c
c,然后将
c
c
c的正负与
a
a
a取为一样。
其中当a为负数,我们如果有需求保证
c
c
c为正数可以采用以下处理方法。
c=(c+b)%b=(a%b+b)%b
对于%运算同时还存在以下的特点:
(a*b)%c=((a%c)*(b%c))%c;
(a+b)%c=((a%c)+(b%c))%c;
2.数位拆解
将一个数的每个位数进行拆解然后存储在数组中,一般数学方法和字符串处理两种方法,若题目涉及到数学运算一般采用第一种方法,若直接对输入的数字进行操作得到结果则可以采用第二种方法。
习题链接:
特殊乘法 (九度教程第39题)
反序数(九度教程第 40 题)
对称平方数(九度教程第 41 题)
Digital Root(九度教程第 42 题)
3.进制转换
将k进制数
(
b
n
b
n
−
1
.
.
.
b
3
b
2
b
1
b
0
)
k
(b_nb_{n-1}...b_3b_2b_1b_0)_k
(bnbn−1...b3b2b1b0)k转化为10进制数d:
d
=
b
0
∗
k
0
+
b
1
∗
k
1
+
b
2
∗
k
2
+
,
.
.
.
,
+
b
n
∗
k
n
d=b_0*k^0+b_1*k^1+b_2*k^2+,...,+b_n*k^n
d=b0∗k0+b1∗k1+b2∗k2+,...,+bn∗kn
将10进制数d转化为k进制数:
通过d%k的到当前位,然后执行d=d/k,重复以上操作,直到d=0为止。
之所以上面提到10进制与其他进制之间的相互转换是因为,一般涉及到将m进制转化为n进制的问题,一般会将问题分为以下两个步骤进行求解:
①将m进制转化为10进制
②将10进制转化为n进制
习题链接:
A+B (九度教程第 43题 )
数制转换(九度教程第 44题)
进制转换(九度教程第 45 题)
八进制(九度教程第 46 题)
4.最大公约数(gcd)
对于求解a和b的最大公约数问题,需要分一下三种情况进行讨论。
- 1>a,b均为0,最大公约数不存在
- 2>a,b中有一个为0,另一个不为0,最大公约数为非零的数
- 3>a,b均不为0,则需要按照a=b,b=a%b的过程进行迭代求解,知道b=0时,a即为最大公约数
习题链接:
最大公约数 (九度教程第 47题)
5.最大公倍数(gcd)
两个数的最小公倍数为两数的乘积除以它们的最大公约数。
习题链接:
最小公倍数(九度教程第48题)
Least Common Multiple(九度教程第 49 题)
6.素数筛法
素数筛:
若一个数不是素数,则必存在一个小于它的素数为其的因数。这个命题的正确性是显而易见的。
相关问题涉及到:
判断一个数是否为素数。
找到一个区间内符合某条件的素数。
技巧:打表法
习题链接:
素数判定 (九度教程第 50 题)
素数(九度教程第 51题)
Prime Number(九度教程第 52 题)
Goldbach’s Conjecture(九度教程第53 题)
7.分解素因数
对于所有大于等于2的整数均可以分解成素数的乘积,即其存在一组完全为素数的质因数。
习题链接:
质因数的个数(九度教程第54题)
整除问题(九度教程第 55 题)
8.二分求幂
关于二分幂的求解可以使得求幂的复杂度从O(n)下降到O(logn).
主要代码如下所示:
由于math.h中内置的pow(a,b)函数返回的结果是int类型的因此最终的求解结果很容易就会溢出整形的范围。所以这里我们可以根据快速幂的方法把pow函数改写为返回值为long long类型的,代码片段如下所示:
/*
description:利用二分求幂的方法求解a^b.
*/
long long binaryPower(long long a,long long b){
long long ans=1;
while(b!=0){//equals to b%2==1
if(b&1){
ans*=a;
}
a*=a;
b/=2;
}
return ans;
}
该方法同样适用于矩阵的乘法,同时矩阵的幂次乘法可以用于求解斐波那契数列的第n项(这就是有名的快速幂算法),其时间复杂度为O(2^3*logn),比之间遍历一遍通项公式的O(n)的复杂度大大的下降了,但n的数值非常大的时候,快速幂。在编写矩阵快速幂的时候需要编写矩阵的二分求幂和矩阵乘法运算。
快速幂算法代码如下所示:详细见此博客
#include <iostream>
#include <vector>
using namespace std;
/*
description:利用二分求幂的方法求解a^b.
*/
long long binaryPower(long long a,long long b){
if(b==0)return 1;
long long ans=1;
while(b!=0){//equals to b%2==1
if(b&1){
ans*=a;
}
a*=a;
b>>=1;
}
return ans;
}
/*
description:实现两个矩阵的乘法
*/
vector<vector<int>> matrixMultiple(vector<vector<int>> A,vector<vector<int>>B){
int rowsA = A.size();
int colsA = A[0].size();
int rowsB = B.size();
int colsB = B[0].size();
vector<vector<int>> res;//存储矩阵相乘的结果
if(colsA!=rowsB){
printf("two matrices cannot be multiplied!");
return res;//两矩阵不能相乘,返回空
}
else{
res.resize(rowsA);//初始化结果矩阵的大小
for(int i=0;i<rowsA;i++){
res[i].resize(colsB);
}
for(int i=0;i<rowsA;i++){
for(int j=0;j<colsB;j++){
int sum=0;
for(int k=0;k<colsA;k++){
sum=sum+A[i][k]*B[k][j];
}
res[i][j]=sum;
}
}
}
return res;
}
vector<vector<int>> quickMatrixPower(vector<vector<int>> A,int b){
int rows = A.size();
int cols = A[0].size();
vector<vector<int>> ans;
if(rows!=cols)
{
printf("Only the square matrices can be imaginary!");
return ans;
}
//初始化矩阵ans为单位矩阵
ans.resize(rows);
for(int i=0;i<cols;i++)
ans[i].resize(cols);
ans[0][0]=ans[1][1]=1;
ans[1][0]=ans[0][1]=0;
while(b){//利用二分求幂的方法计算矩阵的幂次方的方法
if(b&1){
ans = matrixMultiple(A,ans);
}
A=matrixMultiple(A,A);
b>>=1;
}
return ans;
}
int main()
{
vector<vector<int>>A ={{1,1},{1,0}};
vector<vector<int>>ans;
ans.resize(2);
for(int i=0;i<2;i++)
ans[i].resize(1);
ans[0][0]=1;
ans[1][0]=1;
int n = 6;
if(n==1)printf("%d\n",1);
if(n==2)printf("%d\n",1);
A = quickMatrixPower(A,n-2);
ans = matrixMultiple(A,ans);
printf("%d\n",ans[0][0]);
return 0;
}
习题链接:
约数的个数(九度教程第 56 题)
人见人爱 A ^ B (九度教程第 57 题)
A sequence of numbers(九度教程第 58 题)
TrA(九度教程第 59 题)(矩阵快速幂,与二分求幂原理相同)
9.高精度整数
题型总结详见该文章:
java–BigInteger神器的开启姿势
习题链接:
a+b(九度教程第 60 题)