Simple Math Problems

最大公约数&最小公倍数

Euclid's Algorithm:若(b eq0),那么(gcd(a,b)=gcd(b,a\%b))
(a<b),定理会先交换a和b。
注意:0和任意正整数a的gcd是a。

int gcd(int a, int b) {
    return !b ? a : gcd(b, a % b);
}

时间复杂度(O(lgb)),因为每次递归问题规模都会缩减一半以上。
最小公倍数(lcm=frac{a*b}{gcd})

  • 扩展欧几里得算法
    可以计算出满足下式的三元组((d,x,y))

[d = GCD(a, b) = ax + by ]

int Euclid_extend(int a, int b, int* x, int* y) {
	if(0 == b) {
		*x = 1;
		*y = 0;
		return a;
	}
	else {
		int r = Euclid_extend(b,a%b,x,y);
		int temp = *x;
		*x = *y;
		*y = temp - (*y)*(a/b);
		return r;
	}
}

简单证明:
(b=0)是递归基,易得一组解(x=1,y=0);
(b eq0)时:
首先递归求解:

[d'=gcd(b,a\%b)=bx'+(a\%b)y' (1) ]

我们知道:

[d=gcd(a,b)=d'=gcd(b,a\%b) (2) ]

[a\%b=a-b*iggllfloor a/b iggr floor (3) ]

将(2)(3)式带入(1):

[d=bx'+(a-biggllfloor a/b iggr floor)y'=ay'+b(x'-iggllfloor a/b iggr floor y') ]

所以,令(x=y')(y=x'-iggllfloor a/b iggr floor y'),就可以满足(d=ax+by)

分数

PAT甲1088是比较经典的分数处理问题,求2个分数的和、差、积、商,输出最简形式。
表示、化简、运算、输出,代码阐释得很清楚。

#include <cstdio>
#include <algorithm>

using namespace std;

typedef long long ll;

ll gcd(ll a,ll b)
{
        return !b ? a : gcd(b,a % b);
}

struct Fraction{
        ll nume,deno;
};

Fraction reduction(Fraction a)
{
        if(a.deno < 0)
        {
                a.deno = -a.deno;
                a.nume = -a.nume;
        }
        if(a.nume == 0)
        {
                a.deno = 1;
        }
        else
        {
               int d = gcd(abs(a.nume),abs(a.deno));
               a.nume /= d;
               a.deno /= d;
        }
        return a;
}

Fraction add(Fraction a,Fraction b)
{
        Fraction res;
        res.deno = a.deno * b.deno;
        res.nume = a.deno * b.nume + a.nume * b.deno;
        return reduction(res);
}

Fraction sub(Fraction a,Fraction b)
{
        Fraction res;
        res.deno = a.deno * b.deno;
        res.nume = a.nume * b.deno - a.deno * b.nume;
        return reduction(res);
}

Fraction times(Fraction a,Fraction b)
{
        Fraction res;
        res.deno = a.deno * b.deno;
        res.nume = a.nume * b.nume;
        return reduction(res);
}

Fraction divide(Fraction a,Fraction b)
{
        Fraction res;
        res.deno = a.deno * b.nume;
        res.nume = a.nume * b.deno;
        return reduction(res);
}

void showFrac(Fraction a)
{
        a = reduction(a);
        if(a.nume < 0)
        {
                printf("(");
        }
        if(a.deno == 1)
        {
                printf("%lld",a.nume);
        }
        else if(abs(a.nume) > abs(a.deno))
        {
                printf("%lld %lld/%lld",a.nume / a.deno,abs(a.nume) % a.deno,a.deno);
        }
        else
        {
                printf("%lld/%lld",a.nume,a.deno);
        }
        if(a.nume < 0)
        {
                printf(")");
        }
}

int main()
{
        Fraction a,b;
        scanf("%lld/%lld%lld/%lld",&a.nume,&a.deno,&b.nume,&b.deno);

        showFrac(a);
        printf(" + ");
        showFrac(b);
        printf(" = ");
        showFrac(add(a,b));
        printf("
");

        showFrac(a);
        printf(" - ");
        showFrac(b);
        printf(" = ");
        showFrac(sub(a,b));
        printf("
");

        showFrac(a);
        printf(" * ");
        showFrac(b);
        printf(" = ");
        showFrac(times(a,b));
        printf("
");

        showFrac(a);
        printf(" / ");
        showFrac(b);
        printf(" = ");
        if(b.nume == 0)
        {
                printf("Inf
");
        }
        else
        {
                showFrac(divide(a,b));
                printf("
");
        }

        return 0;
}

素数

1、判断素数

bool isPrime(int a)
{
        if(a <= 1)   //1不是素数,也不是合数
                return false;
        int tmp = (int)sqrt(1.0 * a);
        for(int i = 2;i <= tmp;i++)
        {
                if(a % i == 0)
                        return false;
        }
        return true;
}

2、打素数表

第一种方法是枚举判断。

const int maxn = 10010;
int prime[maxn],num = 0;

void Prime_table()
{
        for(int i = 2;i < maxn;i++)
        {
                if(isPrime(i))
                {
                        prime[num++] = i;
                }
        }
}

第二种是Eratosthenes筛法,复杂度比枚举更优,代码更短。

/* sieve[k] is false iff k is a prime */
public static boolean[] primes (int n) {
    boolean[] sieve = new boolean[n + 1];
    sieve[0] = sieve[1] = true;

    for (int k = 2; k * k <= n; ++k) {
        if (!sieve[k]) {
            for (int j = k * k; j <= n; j += k) {
                sieve[j] = true;
            }
        }
    }
    return sieve;
}

3、分解质因子
注意:1要特判。

//存储
struct factor{
        int x,cnt; //x为质因子,cnt为该质因子个数
}fac[20];
int num = 0;  //记录不同因子个数
//枚举小于等于sqrt(n)内的所有质因子,判断哪个是n的因子
for(int i = 0;prime[i] <= sqrt(n);i++)
{
        if(n % prime[i] == 0)
        {
                fac[num].x = prime[i];
                fac[num].cnt = 0;
                while(n % prime[i] == 0)
                {
                        fac[num].cnt++;
                        n /= primep[i];
                }
                num++;
        }
}

//如果n仍然大于1,说明n有一个大于sqrt(n)的质因子
if(n != 1)
{
        fac[num].x = n;
        fac[num++].cnt = 1;
}
原文地址:https://www.cnblogs.com/EIMadrigal/p/12130450.html