文章目录
一、最大公约数与最小公倍数
1.1 最大公因式
//最大公因式
int gcd(int a,int b){
return !b ? a : gcd(b , a % b);
}
1.2 最小公倍数
//最小公倍数
int lcm(int a,int b){
int d = gcd(a , b);//d保存a与b的最小公倍数
return a / d * b;
}
二、素数
2.1 素数判断
bool isPrime(int n){
if(n<=1) return false;
for(int i=2; i*i<=n; i++){
if (n % i == 0) return false;
}
return true;
}
2.2 素数表获取
//求解100以内的所有素数
const int maxn = 101;//表长
int prime[maxn], pnum=0; //前者存放所有的素数,后者存放素数个数
void Find_Prime(){
for(int i = 1; i < maxn; i++){
//判断是否为素数
if(isPrime(i) == true){
prime[num++] = i;
}
}
}
三、质因子分解
质因子分解:将一个正整数n写成一个或多个质数的乘积的形式。由于每个质因子出现不止一次,因此定义结构体factor,用来存放质因子及其个数。
struct factor{
int x,cnt;
}fac[10];//对于int型,数组开到10即可
//质因子分解(分解 int n)
//1、枚举1~sqrt(1.0*n)内所有质数p,判断p是否是n的因子
int n, num=0;
for(int i = 0; prime[i] <= sqrt(1.0 * n) && i < pnum; i++){//prime[i]存放整数n所有的素数, pnum为整数n的质数个数
if(n % prime[i] == 0){//记录该质因子
fac[num].x = prime[i];
fac[num].cnt = 0;
while(n % prime[i] == 0){
fac[num].cnt++;
n/=prime[i];
}
num++;
}
if(n == 1) break;
}
//2、如果上述结束后,n还是大于1,说明n有且只有一个大于sqrt(1.0*n)的质因子(可能是n本身)(如6=2 x 3, 3大于根号6)
if(n != 1){
fac[num].x = n;
fac[num++].cnt = 1;
}
四、分数的四则运算
4.1 分数的表示
struct Fraction{
int up,down;
};
4.2 分数的化简
Fraction reduction(Fraction result){
if(result.down<0){//分母小于零
result.up = -result.up;
result.down = -result.down;
}
if(result.up == 0){
result.dpwn = 1;
}else{
int d = gcd(abs(result.up), abs(result.down));//求分子分母的最大公因式
result.up /= d;
result.down /= d;
}
return result;
}
4.3 分数加法
Fraction add(Fraction f1, Fraction f2){
Fraction result;
result.up = f1.up * f2.down + f1.down * f2.up;
result.down = f1.down * f2.down;
return reduction(result);
}
4.4 分数减法
Fraction sub(Fraction f1, Fraction f2){
Fraction result;
result.up = f1.up * f2.down - f1.down * f2.up;
result.down = f1.down * f2.down;
return reduction(result);
}
4.5 分数乘法
Fraction multi(Fraction f1, Fraction f2){
Fraction result;
result.up = f1.up * f2.up;
result.down = f1.down * f2.down;
return reduction(result);
}
4.6 分数除法
Fraction divide(Fraction f1, Fraction f2){
Fraction result;
result.up = f1.up * f2.down;
result.down = f1.down * f2.up;
return reduction(result);
}
4.7 分数的输出
void showResult(Fraction f){
r = reduction(r);
if(r.down == 1) printf("%d", r.up); //整数
else if(abs(r.up) > r.down){//假分数
printf("%d %d/%d", r.up / r.down, abs(r.up) % r.down, r.down);
}else{//真分数
printf("%d/%d", r.up, r.down);
}
}
五、进制转换
5.1 任意进制转换为十进制
以二进制转换为十进制为例:
基本规则:把二进制数按权展开、相加即得十进制数。
int toDecimal(string s, int radix){ //s是给定的radix进制字符串
int ans =0;
for(int i = 0; i < s.size(); i++){
char t = s[i];
if(t >= '0' && t <= '9') ans = ans * radix + (t - '0');
else ans = ans * radix + (t - 'a' + 10);
}
return ans;
}
5.2 十进制转换为其他进制
5.2.1 方法一
以十进制转换为二进制为例:
基本规则:十进制数除2取余法,即十进制数除2,余数为权位上的数,得到的商值继续除,直到商为0为止。
string decimalToA(int n, int radix){//n是待转数字(十进制),radix是需转换为的进制
string ans = "";
do{
int t = n % radix;
if(t >= 0 && t <= 9) ans += t + '0';//将数字转换为字符
else ans += t - 10 + 'a';//转换为相应的字母,比如讲十进制的11转换为16进制的b
n /= radix;
}while(n != 0); //使用do{}while()以防止输入为0的情况
reverse(ans.begin(), ans.end());
return ans;
}
5.2.2 方法二
itoa()函数(可以将一个10进制数转换为任意的2-36进制字符串)
用法:charitoa(int value,charstring,int radix);
六、大整数运算
6.1 大整数存储
struct bign{
int d[1000];
int len;
bign(){
memset(d, 0, sizeof(d));
len = 0;
}
};
//按字符串%s读入时,数组高位存储整数低位,需要反转一下,使整数高位存储在数组高位
bign change(char str[]){
bign a;
a.len = strlen(str);
for(int i = 0; i < a.len; i++){
a.d[i] = str[a.len - 1 - i] - '0';
}
return a;
}
6.2 比较大小
int compare(bign a, bign b){//比较a和b大小,a大、相等、a小分别返回1、0、-1
if(a.len > b.len) return 1;//a大
else if(a.len < b.len) return -1;//b大
else{
for(int i = a.len - 1; i >= 0; i--){//从高位比较
if(a.d[i] > b.d[i]) return 1;//a大
else if(a.d[i] < b.d[i]) return -1;
}
}
return 0;//两数相等
}
6.3 高精度加法
bign add(bign a, bign b){
bign result;
int carry = 0;//进位
for(int i = 0; i < a.len || i < b.len; i++){//以较长的一方为界限
int temp = a.d[i] + b.d[i] + carry;
result.d[result.len++] = temp % 10;//大数result低位保留大数a、b低位相加的结果temp的个位
carry = temp / 10;//temp的高位为进位
}
if(carry != 0){//加法的进位最多只能有一位,如果最后的进位不为0,直接复制给结果最高位
result.d[result.len++] = carry;
}
return result;
}
6.4 高精度减法
//如果被减数小于减数,需要交换两个变量,输出负号,然后在调用sub()
bign sub(bign a, bign b){
bign result;
for(int i = 0; i < a.len || i < b.len; i++){
if(a.d[i] < b.d[i]){//不够减
a.d[i+1]--;//向高位借位
a.d[i] += 10;
}
result.d[result.len++] = a.d[i] - b.d[i];//保留当前的减法结果
}
while(result.len > 1 && result.[result.len - 1] == 0){
result.len--;
}
return result;
}
6.5 高精度与低精度的乘法
bign multi(bign a, int b){
bign result;
int carry = 0;//进位
for(int i = 0; i < a.len; i++){
int temp = a.d[i] * b + carry;
result.d[result.len++] = temp % 10;//个位为该位结果
carry = temp / 10;//其他位作为进位
}
while(carry != 0){//乘法的进位可能不止一位
result.d[result.len++] = carry % 10;
carry /= 10;
}
return result;
}
6.6 高精度与低精度的除法
bign divide(bign a, int b, int& r){//a为被除数,b为除数,r为余数
bign result;
result.len = a.len;//除数位数与商的位数一一对应
for(int i = a.len - 1; i >= 0; i--){//从高位开始
r = r * 10 +a.d[i];//和上一位遗留的余数组合
if(r < b) result.d[i] = 0;//不够除,商该位为0
else{
result.d[i] = r / b;
r = r % b;//更新余数
}
}
while(result.len > 1 && result.d[result.len - 1] == 0){
c.len--;
}
return result;
}