typedef long long LL;
组合数
LL C(LL n, LL m)
{
if (m < n - m)
m = n - m;
LL ans = 1;
for (LL i = m + 1; i <= n; i++)
ans = ans * i % mod;
for (LL i = 1; i <= n - m; i++)
ans = ans * Inv(i, mod) % mod; // 不取mod 改成 / i
return ans;
}
欧拉筛法即线性筛
const int maxm = 10000000 + 5;
bool isprime[maxm]; //若1为素数 若0不是素数
int su[maxm];
int cnt = 0;
void prime()
{
memset(isprime, true, sizeof isprime);
memset(su, 0, sizeof su);
isprime[0] = isprime[1] = false; // 0 和 1 不是素数
for (int i = 2; i <= maxm; i++)
{
if (isprime[i])
su[++cnt] = i;
for (int j = 1; j <= cnt && i * su[j] <= maxm; j++)
{
isprime[i * su[j]] = false;
if (i % su[j] == 0)
break;
}
}
}
欧几里德
int gcd(int a, int b)
{
return b == 0 ? a : gcd(b, a % b);
}
扩展欧几里德
int ex_gcd(int a, int b, int &x, int &y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
else
{
int d = ex_gcd(b, a % b, x, y);
int t = x;
x = y;
y = t - (a / b) * y;
return d;
}
}
快速幂
LL qpow(LL a, LL b, LL c)
{
LL ans = 1;
while (b)
{
if (b & 1)
ans = ans * a % c;
a = a * a % c;
b = b >> 1;
}
return ans;
}
快速乘
LL qmul(LL a, LL b)
{
LL ans = 0;
while (b)
{
if (b & 1)
ans = ans + a;
a = a * 2;
b = b >> 1;
}
return ans;
}
乘法逆元
这位博主说得挺好的https://www.cnblogs.com/zjp-shadow/p/7773566.html
扩展欧几里德求逆元
void Ex_gcd(LL a, LL b, LL &x, LL &y)
{
if (!b)
x = 1, y = 0;
else
Exgcd(b, a % b, y, x), y -= a / b * x;
}
int main()
{
LL x, y;
Ex_gcd(a, p, x, y);
x = (x % p + p) % p;
printf("%d\n", x); //x是a在mod p下的逆元
}
费马小定理即快速幂求逆元
LL Inv(LL a, LL p)
{
return qpow(a, p - 2, p);
}
线性递推求逆元
LL n, p;
cin >> n >> p;
inv[1] = 1;
for (int i = 2; i <= n; i++)
{
inv[i] = p - p / i * inv[p % i] % p;
}
质因数分解
int a[maxn]; // a[i] 表示 第i个质因数的值
int b[maxn]; // b[i] 表示第i个质因数的指数
int tot; // 不同的质因数的个数
void factor(int n, int *a, int *b, int &tot)
{
tot = 0;
int t, now = n;
t = (int)((double)sqrt(n) + 1);
for (int i = 2; i <= t; i++)
{
if (now % i == 0)
{
a[++tot] = i;
b[tot] = 0;
while (now % i == 0)
{
++b[tot];
now /= i;
}
}
}
if (now != 1)
{
a[++tot] = now;
b[tot] = 1;
}
}
欧拉函数(小于n且与n互素的整数个数)
int euler_phi(int n)
{
int m = (int)sqrt(n + 0.5);
int ans = n;
for (int i = 2; i <= m; i++)
{
if (n % i == 0)
{
ans = ans / i * (i - 1);
while (n % i == 0)
n /= i;
}
}
if (n > 1)
ans = ans / n * (n - 1);
return ans;
}
1~n中所有数的欧拉phi函数值 O(nloglogn)
void phi_table(int n)
{
for (int i = 2; i <= n; i++)
phi[i] = 0;
phi[1] = 1;
for (int i = 2; i <= n; i++)
{
if (!phi[i])
{
for (int j = i; j <= n; j += i)
{
if (!phi[j])
phi[j] = j;
phi[j] = phi[j] / i * (i - 1);
}
}
}
return;
}
筛完素数后求因子个数 跟上面的欧拉筛是配合的
LL count_divisor(LL n)
{
LL s = 1;
for (int i = 0; i <= cnt && su[i] * su[i] <= n; i++)
{
if (n % su[i] == 0)
{
LL a = 0;
do
{
n = n / su[i];
a++;
} while (n % su[i] == 0);
s = s * (a + 1);
}
}
if (n > 1)
s = s * 2;
return s;
}