代码来源:晴神《算法笔记》!!
一. 最大公约数
int gcd(int a, int b){
if(b == 0) return a;
else return gcd(b, a%b);
}
二. 最小公倍数
lcm(a, b) = ab / d,ab有可能溢出,因此更恰当的写法是a/d*b。
三. 分数的四则运算
分数的表示
struct fraction{
int up, down;
};
分数的化简
fraction reduction(fraction a){
if(a.down < 0){
a.up = -a.up;
a.down = -a.down;
}
if(a.up == 0)
a.down = 1;
else{
int d = gcd(abs(a.up), abs(a.down));
a.up /= d;
a.down /= d;
}
return a;
}
分数的加法
fraction add(fraction a, fraction b){
fraction res;
res.up = a.up*b.down + a.down*b.up;
res.down = a.down*b.down;
return reduction(res);
}
减、乘、除类似,除法需判断除数是否为0,略
分数的输出
void showres(fraction r){
r = reduction(r);
if(r.down == 1) printf("%lld",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);
}
一般情况下,计算过程中,分子或者分母有可能超出int范围,因此最好用long long存储。
四. 素数
判断是否是素数
bool isprime(int n){
if(n <= 1) return false;
int sqr = (int)sqrt(1.0*n); //要求是浮点数
for(int i = 2; i <= sqr; i++){
if(n % i == 0) return false;
}
return true;
}
素数表的获取
const int maxn = 101;
int prime[maxn], pnum = 0;
bool p[maxn] = {0};
void find_prime(){
for(int i = 2; i < maxn; i++){
if(p[i] == false){
prime[pnum++] = i;
for(int j = i + i; j < maxn; j+=i){
p[j] = true;
}
}
}
}
五. 质因子分解
对于一个正整数n来说,如果它存在[2,n]范围内的质因子,要么这些质因子全部小于等于sqrt(n),要么只存在一个大于sqrt(n)的质因子,而其余质因子全部小于等于sqrt(n)。
struct factor{
int x, cnt;
}fac[10]; //只需要开到10即可
//在1-sqrt(n)范围内
for(int i = 0; i < pnum && prime[i] <= sqr; i++){
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;
}
//如果结束后n仍大于1
if(n != 1){
fac[num].x = n;
fac[num++].cnt = 1;
}
六. 大整数运算
存储
struct bign{
int d[1000];
int len;
bign(){ //初始化
memset(d,0,sizeof(d));
len = 0;
}
};
//字符串读入的时候,整数的高位会变成数组的低位,因此字符串要倒着给bign赋值
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'; //记得要-'0'
}
return a;
}
比较大小
int compare(bign a, bign b){
if(a.len > b.len) return 1;
else if(a.len < b.len) return -1;
else{
for(int i = a.len - 1; i >= 0; i--){ //从高位开始比较
if(a.d[i] > b.d[i]) return 1;
else if(a.d[i] < b.d[i]) return -1;
}
return 0;
}
}
高精度加法
//适用于两个对象都为非负整数
//如果有一方为负,转换为高精度减法;如果都是负的,负号提取
bign add(bign a, bign b){
bign c;
int carry = 0;
for(int i = 0; i < a.len || i < b.len; i++){ //以较长的为界限
int temp = a.d[i] + b.d[i] + carry; //记得加上进位
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
if(carry != 0){
c.d[len++] = carry;
}
return c;
}
高精度减法
//先比较大小,如果被减数不够减,交换两个变量,最后输出负号
bign sub(bign a, bign b){
bign c;
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;
}
c.d[c.len++] = a.d[i] - b.d[i];
}
//去掉高位多余的0,但也要保证至少有一位
while(c.len - 1 >= 1 && c.d[len-1] == 0){
c.len--;
}
return c;
}
高精度与低精度的乘法
//如果有负数,先记录下负号,把绝对值代入
bign mul(bign a, int b){
bign c;
int carry = 0;
for(int i = 0; i < a.len; i++){
int temp = a.d[i] * b + carry;
c.d[c.len++] = temp % 10;
carry = temp / 10;
}
while(carry != 0){
c.d[c.len++] = carry % 10;
carry /= 10;
}
return c;
}
高精度与低精度的除法
bign devide(bign a, int b, int &r){ //r为余数
bign c;
c.len = a.len;
for(int i = a.len - 1; i >= 0; i--){
r = r * 10 + a.d[i];
if(r < b) c.d[i] = 0;
else{
c.d[i] = r / b;
r = r % b;
}
}
while(c.len - 1 >= 1 && c.d[len-1] == 0){
c.len--;
}
return c;
}