1.进制转换
对于不大的输入,可以借助向量,模一次存一次整除一次,倒序输出即可;而对于过长位数的输入,则应使用字符串来模拟数字的模运算和整除运算
1.1 十进制->二进制->十进制 (十进制数的位数<=1000)
十进制->二进制时要用到字符串除法;二进制->十进制时要用到字符串乘法+字符串加法
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
using namespace std;
string strDivide(string str,int x)//字符串除法
{
int remainder=0;//保存余数
for(int i=0;i<str.size();++i)//从高位到低位
{
int current=remainder*10+str[i]-'0';//上一次保留的余数x10与本次第一位的数一起处理
str[i]=current/x+'0';
remainder=current%x;//不能整除则保留余数
}
int pos=0;//标记非前导0的位数
while(str[pos]=='0')
pos++;
return str.substr(pos);//删除前导0
}
string strMultiple(string str,int x)//字符串乘法
{
int carry=0;//保存进位
for(int i=str.size()-1;i>=0;--i)
{
int current=x*(str[i]-'0')+carry;
str[i]=current%10+'0';
carry=current/10;
}
if(carry!=0)//若仍有进位,则在结果前面补1
str="1"+str;
return str;
}
string strAdd(string str,int x)//字符串加法
{
int carry=x;//保存进位,这一步与字符串乘法不同
for(int i=str.size()-1;i>=0;--i)
{
int current=(str[i]-'0')+carry;//这一步与字符串乘法不同
str[i]=current%10+'0';
carry=current/10;
}
if(carry!=0)//若仍有进位,则在结果前面补1
str="1"+str;
return str;
}
int main()
{
string str;
while(cin>>str)
{
vector<int> binary;
//十进制->二进制
while(str.size()!=0)//类似与整数的直接进制转换
{
int last=str[str.size()-1]-'0';//取最低位的值
binary.push_back(last%2);//取模
str=strDivide(str,2);//整除运算
}//获得二进制串(反序的
//二进制->十进制
string answer="0";
for(int i=0;i<binary.size();++i)
{
answer=strMultiple(answer,2);
answer=strAdd(answer,binary[i]);
}
cout<<answer<<endl;
}
return 0;
}
1.2 M进制的数输出为N进制的数
中间转换为十进制作为过渡,涉及到字符与数字之间的转换,超过十进制就要带上字母
https://www.nowcoder.com/practice/ae4b3c4a968745618d65b866002bbd32?tpId=40&tqId=30990&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking
#include<iostream>
#include<cstdio>
#include<string>
#include<vector>
using namespace std;
char int2char(int x)//数字->字符
{
if(x<10)
return x+'0';
else//大于9的数字转换为a,b,c......
return x-10+'a';
}
int char2int(char c)//字符->数字
{
if(c>='0'&&c<='9')
return c-'0';
else//a,b,c...转换为10,11,12......
return c-'A'+10;
}
int main()
{
int m,n;
string x;
while(cin>>m>>n)
{
cin>>x;
//M进制转化为十进制
long long number=0;
for(int i=0;i<x.size();++i)
{
number*=m;
number+=char2int(x[i]);
}
//十进制转化为N进制
vector<char> answer;
while(number!=0)
{
answer.push_back(int2char(number%n));
number/=n;
}
//倒序输出
for(int i=answer.size()-1;i>=0;--i)
{
cout<<answer[i];
}
cout<<endl;
}
return 0;
}
2. 最大公约数与最小公倍数
2.1 最大公约数GCD
原理:欧几里得算法(辗转相除):a,b的公约数g可整除“a除以b后的余数r”,则问题转换为球b,(a mod b)的最大公约数,不断重复直至问题变为球某个非零数与0的最大公约数,该非零数即为答案
int GCD(int a,int b)
{
if(n==0)
return a;
else
return GCD(b,a%n);
}
2.2 最小公倍数LCM
a,b两个数的最小公倍数是两者的乘积÷两者的最大公约数
3. 质数(素数)
质数是只能被1和自己整除的数。
3.1 一般方法
找素数只需遍历到sqrt(n),适合判定某数是否是素数的情况
bool Judge(int x)
{
if(x<2)
return false;
int bound=sqrt(x);//判断上界
for(int i=2;i<=bound;++i)
{
if(x%i==0)
return false;
}
return true;
}
3.2 素数筛法
找到一个素数后就把它的倍数也标记为素数。适合找出某个大范围内的所有素数的情况
vector<int> prime;
bool isPrime[MAXN];
void Initial()//把非质数标记出来,剩下的就是质数
{
//初始化
for(int i=0;i<MAXN;++i)
isPrime[i]=true;
isPrime[0]=false;
isPrime[1]=false;
//遍历
for(int i=2;i<MAXN;++i)
{
if(!isPrime[i])//跳过非质数
continue;
prime.push_back(i);
for(int j=i*i;j<MAXN;j+=i)//质数的背书为非质数
isPrime[i]=false
}
return;
}
4. 分解质因数
每一个数字都可以写成多个质数相乘的形式,而其中各种质数就是这个数字的质因数。只需遍历到N的开方,而非1e9是因为n最多只有一个>sqrt(n)的因子;若有两个,乘积就大于n了
//用素数筛法,确定0到MAXN内的所有素数
//输入n,依次测试能否整除n,能则计数
//不断将n除以该素数,直至不能整除,统计其幂指数
//遍历所有的素数后,若n=1,则分解完成;否则n存在一个大于MAXN的因子,这个因子必为素因子
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
const int MAXN=100001;//使用素数筛法只需找到N的开方即可
vector<int> prime;
bool isPrime[MAXN];
void Initial()//素数筛法
{
for(int i=0;i<MAXN;++i)
isPrime[i]=true;
isPrime[0]=false;
isPrime[1]=false;
for(int i=2;i<MAXN;++i)
{
if(!isPrime[i])
continue;
prime.push_back(i);
for(int j=i*i;j<MAXN;j+=i)
isPrime[j]=false;
}
}
int main()
{
Initial();
int n;
while(cin>>n)
{
int answer=0;
for(int i=0;i<prime.size()&&prime[i]<n;++i)
{
int factor=prime[i];
while(n%factor==0)//不断试除
{
n/=factor;
answer++;
}
}
if(n>1)//还剩一个质因数
answer++;
cout<<answer<<endl;
}
return 0;
}
5. 快速幂
求某个数的高次幂时,不用一次一次地乘这个数,而可以使用若干个中间结果的平方,以此减少乘的次数
例题:求A^B的最后三位数
输入:每行输入都是A和B,输入0 0时结束输入,且1<=A,B<=10000
输出:A^B结果后三位形成的整数
#include<iostream>
#include<cstdio>
using namespace std;
int FastMi(int a,int b,int mod)
{
int answer=1;
while(b!=0)//不断将b转换为二进制数,其中1代表乘一次a,0代表不乘
{
if(b%2==1)//若当前位为1
{
answer*=a;
answer%=mod;
}
b/=2;
a*=a;//二进制的下一位对应的乘a次数增加,所以这里a自乘
a%=mod;//保存后几位
}
return answer;
}
int main()
{
int a,b;
while(cin>>a>>b)
{
if(a==0&&b==0)
break;
cout<<FastMi(a,b,1000)<<endl;//保存后三位,所以mod取1000
}
return 0;
}
6. 矩阵与矩阵快速幂
6.1 矩阵乘法
按照线性代数正常运算
struct Matrix
{
int matrix[MAXN][MAXN];
int row,col;//行,列
Matrix(int r,int c):row(r),col(c) {}
};
Matirx Multiply(Matrix x,Matrix y)
{
Matrix answer(x.row,y.col);
for(int i=0;i<answer.row;++i)//前两层循环用于遍历
{
for(int j=0;j<answer.col;++j)
{
answer.matrix[i][j]=0;
for(int k=0;k<x.col;++k)//计算
answer.matrix[i][j]+=x.matrix[i][k]*y.matrix[k][j];
}
}
return answer;
}
6.2 矩阵快速幂
矩阵乘法+快速幂
#include<iostream>
#include<cstdio>
using namespace std;
struct Matrix
{
int matrix[10][10];
int row,col;//行,列
Matrix(int r,int c):row(r),col(c) {}
};
Matrix Multiply(Matrix x,Matrix y)
{
Matrix answer(x.row,y.col);
for(int i=0;i<answer.row;++i)//前两层循环用于遍历
{
for(int j=0;j<answer.col;++j)
{
answer.matrix[i][j]=0;
for(int k=0;k<x.col;++k)//计算
answer.matrix[i][j]+=x.matrix[i][k]*y.matrix[k][j];
}
}
return answer;
}
void PrintMatrix(Matrix x)
{
for(int i=0;i<x.row;++i)
{
for(int j=0;j<x.col;++j)
{
if(j!=0)
cout<<" ";
cout<<x.matrix[i][j];
}
cout<<endl;
}
return ;
}
Matrix FastMi(Matrix x,int k)//x矩阵的k次幂
{
Matrix answer(x.row,x.col);
for(int i=0;i<answer.row;++i)//矩阵的快速幂需要初始化为单位矩阵
{
for(int j=0;j<answer.col;++j)
{
if(i==j)
answer.matrix[i][j]=1;
else
answer.matrix[i][j]=0;
}
}
while(k!=0)//类似正常的快速幂
{
if(k%2==1)
answer=Multiply(answer,x);
k/=2;
x=Multiply(x,x);
}
return answer;
}
int main()
{
int n,k;
while(cin>>n>>k)
{
Matrix x(n,n);
for(int i=0;i<n;++i)//输入矩阵
{
for(int j=0;j<n;++j)
{
cin>>x.matrix[i][j];
}
}
Matrix answer=FastMi(x,k);
PrintMatrix(answer);
}
return 0;
}
7. 高精度整数
使用Java中的BigInteger类,或使用C++高精度整数模板