数论板子

//筛法求MAXN范围以内的素数表,其中需要借用一个bool数组vis  
void prime_table()   
{  
    int i,j;  
    for(i = 2;i <= MAXN;i++)  
    {  
        if(!vis[i])  
        {  
            prime[++cnt] = i;                //cnt为素数计数器  
            for(j = i*i;j <= MAXN;j += i)  
                vis[j] = true;  
        }  
    }  
}  
//高效算法同时打出prime表与phi表,比单独用筛法打出phi表与prime表快3倍左右
void prime_phi_table()
{
    int i,j;
    phi[1] = 1;
    for(i = 2;i <= MAXN;i++)
    {
        if(!vis[i])
        {
            prime[++cnt] = i;
            phi[i] = i-1;
        }
        for(j = 1;j <= cnt && i * prime[j] <= MAXN;j++)
        {
            vis[i * prime[j]] = true;
            if(i % prime[j] == 0)
            {
                phi[i * prime[j]] = phi[i] * prime[j];
                break;
            }
            else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
        }
    }
}
//求n的欧拉函数值  
int phi(int n)  
{  
    int t = sqrt(n + 0.5);  
    int ans = 1;  
    for(int i = 2;i <= t;i++)  
    {  
        if(n % i == 0)  
        {  
            ans *= (i-1);  
            n /= i;  
            while(n % i == 0)  
            {  
                ans *= i;  
                n /= i;  
            }  
        }  
        if(n == 1) break;  
    }  
    if(n > 1) ans *= (n-1);  
    return ans;  
}  
//求a与b的最大公约数,其中b > a  
int gcd(int a,int b)   
{  
    if(a > b) swap(a,b);  
    while(a)  
    {  
        int t = b % a;  
        b = a;  
        a = t;  
    }  
    return b;  
}  
//扩展欧几里得,ax + by = c,求出x,y的一组整数解,d = gcd(a,b),当 c % d != 0时,无整数解  
void exgcd(int a,int b,int &d,int &x,int &y)  
{  
    if(!b) {d = a; x = 1; y = 0;}  
    else {  
            exgcd(a%b,a,d,y,x);  
            y -= x*(a/b);  
    }  
}  
"code" class="cpp">//在上述不定方程中,若方程为ax + by = gcd(a,b),当求出一组整数解x0,y0后  
//关于x,y的通解则有:x = x0 + b/d * k , y = y0 - a/d * t (t为任意整数)  
[cpp] view plain copy
"code" class="cpp">//由于模运算的特殊性,在计算(a / b) % m 时,当a、b太大需要事先取模,此时该式不能直接写为:  
// ((a % m) / (b % m)) % m  
// 而是需要先算出 ax≡1(mod m),此时x为a的逆元。这个式子等价于ax + my = 1(此时gcd(a,b)必须为1,否则无解)  
// 此时使用扩展欧几里得即可解决:exgcd(a,m,d,x,y);当m为质数时,x = (a^(m-2)) % m;  
//但求出来的x可能为负数,需要写成(x + m) % m  
// 最终式子为 (a / b) % m = a * x % m  
//对整数n进行唯一分解,A[cnt].prime为n的第cnt个质因子,A[cnt].num为该质因子的指数  
void dissolve(int n)  
{  
    int i;  
    int t = sqrt(n + 0.5);  
    for(i = 2;i <= t;i++)  
    {  
        if(n % i == 0)  
        {  
            cnt++;  
            A[cnt].prime = i;  
            while(n % i == 0)  
            {  
                A[cnt].num++;  
                n /= i;  
            }  
        }  
        if(n == 1) break;  
    }  
    if(n > 1)                     //若n为质数  
    {  
        cnt++;  
        A[cnt].prime = n;  
        A[cnt].num = 1;  
    }  
}  
//求1~n行的组合数,即杨辉三角表,注意,为了防止数组越界,此时C(0,0)为数组第一行,且第n行代表C(n-1,k)  
void Make_up_num_table(int n)  
{  
    C[1][1] = 1;  
    C[2][1] = 1; C[2][2] = 1;  
    for(int i = 3;i <= n;i++)  
        for(j = 1;j <= i;i++)  
            C[i][j] = C[i-1][j-1] + C[i-1][j];  
}  
[cpp] view plain copy
//求第n行的组合数,和杨辉三角的区别是这个只求一行但是为O(n)的时间复杂度  
//注意,这个函数出于求解方便,第n行代表的是C(n,k)且是从0开始存,与上一个函数不同  
void Make_up_num(int n)  
{  
    A[0] = 1;  
    for(int i = 1;i <= n;i++)  
        A[i] = A[i-1] * (n - i + 1) / i;  
}  

你可能感兴趣的:(NOIP,算法)