PAT:常见数学问题模板

本文对PAT中常见数学问题用到的模板进行了归纳:

1.最大公约数与最小公倍数

int gcd(int a, int b){//求取最大公约数
    return !b ? a : gcd(b, a%b);
}

int lcm(int a, int b){//求取最小公倍数
    return a / gcd(a,b) * b;    //先除后乘以避免溢出
}

2.分数

//注意,一般分数的分子分母用long long表示更保险,因为有时做运算时会导致int溢出
struct Fraction{//分数
    int up, down;   //分子与分母
};

Fraction reduction(Fraction result){//分数化简
    if(result.down < 0){
        result.up = - result.up;
        result.down = -result.down;
    }
    if(!result.down)    result.up = 1;
    else{
        int d = gcd(abs(result.up), abs(result.down));  //注意此处使用绝对值来求取最大公约数
        result.up /= d;
        result.down /= d;
    }
    return result;
}

void showResult(Fraction r){//分数输出
    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);
}

3.素数

bool is_prime(int n){//判断素数
    if(n <= 1)  return false;
    int sqrn = (int)sqrt(1.0 * n);
    for(int i = 2; i <= sqrn; i++){//记住是从2开始,并且后面是小于等于号
        if(n % i == 0)  return false;
    }
    return true;
}

4.大整数运算

注意有负数时,先转换为正数,再确定最终的运算方式以及输出形式。

//大整数定义
struct bign{
    int d[1000];
    int len;
    bign(){
        memset(d, 0, sizeof(d));
        len = 0;
    }
};

//大整数转换
bign change(string str){
    bign a;
    a.len = str.size();
    for(int i = 0; i < a.len; i++){
        a.d[i] = str[a.len-1-i] - '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++){
        c.d[c.len++] = (a.d[i] + b.d[i] + carry) % 10;
        carry = (a.d[i] + b.d[i] + carry) / 10;
    }
    if(carry)   c.d[c.len++] = carry;
    return c;
}

//减
bign sub(bign a, bign b){//减之前确保a要大于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];
    }
    //去除前导零
    while(c.len - 1 >= 1 && c.d[c.len - 1] == 0)    c.len--;
    return c;
}

//乘
bign multi(bign a, int b){
    bign c;
    int carry = 0;
    for(int i = 0; i < a.len; i++){
        c.d[c.len++] = (a.d[i] * b + carry) % 10;
        carry = (a.d[i] * b + carry) / 10;
    }
    while(carry){
        c.d[c.len++] = carry % 10;
        carry /= 10;
    }
    return c;
}

//除
bign divide(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[c.len - 1] == 0)    c.len--;
    return c;
}

你可能感兴趣的:(程序员)