线性筛
void get_primes(int n){
for (int i = 2; i <= n; i ++ ){
if (!st[i]) primes[cnt ++ ] = i;
for (int j = 0; primes[j] <= n / i; j ++ ){
st[primes[j] * i] = true;
if (i % primes[j] == 0) break;
}
}
}
n! 的约数个数
int res = 1;
for (int i = 0; i < cnt; i ++ ){
int p = primes[i];
int s = 0;
for (int j = n; j; j /= p) s += j / p;
res = (LL)res * (2 * s + 1) % mod;
}
约数之和
LL res = 1;
for (auto p : primes){
LL a = p.first, b = p.second;
LL t = 1;
while (b -- ) t = (t * a + 1) % mod;
res = res * t % mod;
}
用到了秦九韶算法
f(x)=a0 + a1x + a2x2 + a3x3 + ⋯ + anxn
f(x)=((⋯(anx + an−1)x + an−2)x + ⋯+a1)x + a0
最大公约数
int gcd(int a, int b){
return b ? gcd(b, a % b) : a;
}
欧拉函数
int res = n;
for(int i = 2;i <= n / i;i ++)
if(n % i == 0){
res = res / i * (i - 1);
while(n % i == 0) n /= i;
}
if(n > 1) res = res / n * (n-1);
素数筛 + 欧拉函数
int primes[N], cnt;
int euler[N];
bool st[N];
void get_eulers(int n){
euler[1] = 1;
for (int i = 2; i <= n; i ++ ){
if (!st[i]){
primes[cnt ++ ] = i;
euler[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++ ){
int t = primes[j] * i;
st[t] = true;
if (i % primes[j] == 0){
euler[t] = euler[i] * primes[j];
break;
}
euler[t] = euler[i] * (primes[j] - 1);
}
}
}
快速幂
LL qmi(int a, int b, int p) {
LL res = 1 % p;
while (b){
if (b & 1) res = res * a % p;
a = a * (LL)a % p;
b >>= 1;
}
return res;
}
矩阵快速幂
acwing.1305.GT考试
#include <cstring>//矩阵快速幂
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 25;
int n, m, mod;
char str[N];
int ne[N];
int a[N][N];
void mul(int c[][N], int a[][N], int b[][N]) { // c = a * b
static int t[N][N];
memset(t, 0, sizeof t);
for (int i = 0; i < m; i ++ )
for (int j = 0; j < m; j ++ )
for (int k = 0; k < m; k ++ )
t[i][j] = (t[i][j] + a[i][k] * b[k][j]) % mod;
memcpy(c, t, sizeof t);
}
int qmi(int k){
int f0[N][N] = {1};
while (k){
if (k & 1) mul(f0, f0, a); // f0 = f0 * a
mul(a, a, a); // a = a * a
k >>= 1;
}
int res = 0;
for (int i = 0; i < m; i ++ ) res = (res + f0[0][i]) % mod;
return res;
}
int main()
{
cin >> n >> m >> mod;
cin >> str + 1;
// kmp
for (int i = 2, j = 0; i <= m; i ++ ){
while (j && str[j + 1] != str[i]) j = ne[j];
if (str[j + 1] == str[i]) j ++ ;
ne[i] = j;
}
// 初始化A[i][j]
for (int i = 0; i < m; i ++ )
for (int c = '0'; c <= '9'; c ++ ){
int j = i;
while (j && str[j + 1] != c) j = ne[j];
if (str[j + 1] == c) j ++ ;
if (j < m) a[i][j] ++;
}
// F[n] = F[0] * A^n
cout << qmi(n) << endl;
return 0;
}
扩展欧几里得
裴蜀定理
int exgcd(int a, int b, int &x, int &y){
if (!b){
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
组合数C ( DP求解 ) ( 复杂度 N ^2 )
void init(){
for (int i = 0; i < N; i ++ )
for (int j = 0; j <= i; j ++ )
if (!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
组合数C ( 阶乘 + 逆元 ) ( 复杂度 N * logN)
int qmi(int a, int k, int p){
int res = 1;
while (k){
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
void jie(){
fact[0] = infact[0] = 1;
for (int i = 1; i < N; i ++ ){
fact[i] = (LL)fact[i - 1] * i % mod;
infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod;
//infact[i] = (LL)qmi(fact[i], mod - 2, mod) % mod; 这两行都行
}
}
printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);//输出Cab
组合数C ( 卢卡斯定理 ) ( 复杂度 mod * log mod)
int lucas(LL a, LL b, int p){
if (a < p && b < p) return C(a, b, p);
return (LL)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
//这里的C函数根据数据量变化而改变
//单组查询,直接计算即可
//多组数据,预处理阶乘
}
求组合数 IV ( 高精度 + 分解质因数 )
acwing.1315.网格
#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;
const int N = 5050;
int a, b;
vector <int> res;
int primes[N], cnt;
int st[N];
void init(int t) {
for(int i = 2;i <= t;i ++) {
if(st[i] == 0) primes[cnt ++] = i;
for(int j = 0;i * primes[j] <= t;j ++) {
st[i * primes[j]] = 1;
if(primes[j] % i == 0) break;
}
}
}
int get(int n, int p) {
int ret = 0;
while(n){
ret += n/p;
n /= p;
}
return ret;
}
vector <int> mul(vector <int> v, int t) {
int num = 0;
for(int i = 0;i < v.size();i ++) {
num += v[i] * t;
v[i] = num % 10;
num /= 10;
}
while(num) {
v.push_back(num % 10);
num /= 10;
}
return v;
}
int main(){
cin >> a >> b;
init(a);
res.push_back(1);
for(int i = 0;i < cnt;i ++) {
int l = get(a, primes[i]) - get(b, primes[i]) - get(a-b, primes[i]);
while(l){
res = mul(res, primes[i]);
l --;
}
}
for(int i = res.size() - 1;i >= 0;i --) printf("%d", res[i]);
puts("");
return 0;
}
证明: l c m ( S a , S b ) = S g c d ( a , b ) lcm(\frac{S}{a}, \frac{S}{b})=\frac{S}{gcd(a, b)} lcm(aS,bS)=gcd(a,b)S
l c m ( S a , S b ) = S ∗ l c m ( 1 a , 1 b ) = S ∗ ( a ∗ b ) ∗ l c m ( 1 a , 1 b ) ( a ∗ b ) = S ∗ l c m ( b , a ) ( a ∗ b ) = S ( a ∗ b ) l c m ( b , a ) = S g c d ( a , b ) lcm(\frac{S}{a}, \frac{S}{b})=S*lcm(\frac{1}{a}, \frac{1}{b})=\frac{S*(a*b)*lcm(\frac{1}{a}, \frac{1}{b})}{(a*b)}=\frac{S*lcm(b, a)}{(a*b)}=\frac{S}{\frac{(a*b)}{lcm(b, a)}}=\frac{S}{gcd(a, b)} lcm(aS,bS)=S∗lcm(a1,b1)=(a∗b)S∗(a∗b)∗lcm(a1,b1)=(a∗b)S∗lcm(b,a)=lcm(b,a)(a∗b)S=gcd(a,b)S