//筛法求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);
}
}
<pre name="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
<pre name="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;
}