模板:数学有关

试除法

O ( n ) O(\sqrt{n}) O(n )

bool prime(int n)
{
	if (n < 2) return 0;
	for (int i = 2; i * i <= n; i++)
	if (n % i == 0) return 0;
	return 1;
}
Eratosthenes筛法

O ( n l o g l o g n ) O(n loglogn) O(nloglogn)

inline void primes(int n)
{
	memset(v, 0, sizeof v);
	for (int i = 2; i <= n; i++)
	{
		if (v[i]) continue;
		prime[++cnt] = i;
		for (int j = i; j <= n / i; j++)
		v[i * j] = 1;
	}
}
线性筛法

O ( n ) O(n) O(n)

inline void primes(int n)
{
	memset(v, 0, sizeof v);
	m = 0;
	for (int i = 2; i <= n; i++)
	{
		if (v[i] == 0)
		{
			v[i] = i;
			prime[++m] = i;
		}
		for (int j = 1; j <= m; j++)
		{
			if (prime[j] > v[i] || prime[j] > n / i) break;
			v[i * prime[j]] = prime[j];
		}
	}
	for (int i = 1; i <= m; i++
	printf("%d ", prime[i]);
}
质因数分解

O ( n ) O(\sqrt{n}) O(n )

inline void divide(int n)
{
	m = 0;
	for (int i = 2; i * i <= n; i++)
	{
	 	if (n % i == 0) 
	 	{
	 		p[++m] = i;
	 		c[m] = 0;
	 		while (n % i == 0)
	 		{
	 			n /= i;
	 			c[m]++;
	 		}
	 	}
	 }
	 if (n > 1)
	 {
	 	p[++m] = n;
	 	c[m] = 1;
	 }
}
求 n 的正约数集合(试除法)

O ( n ) O(\sqrt{n}) O(n )

一个整数 n 的约数个数上界为 2 n 2\sqrt{n} 2n

inline void work(int n)
{
	int factor[N], m = 0;
	for (int i = 1; i * i <= n; i++)
	{
		if (n % i == 0)
		{
			factor[++m] = i;
			if (i != n / i) factor[++m] = n / i;
		}
	}
}
求 1 ~ n 每个数的正约数合集(倍数法)

O ( n l o g n ) O(nlogn) O(nlogn)

1 ~ n 每个数的约数个数的总和大约为 n n n\sqrt{n} nn

inline void work(int n)
{
	vector <int> factor[N];
	for (int i = 1; i <= n; i++)
	for (int j = 1; j <= n / i; j++)
	factor[i * j].push_back(i);
}
最大公约数

更相减损术算法性能不稳定,最坏时间复杂度为 O ( m a x ( a , b ) ) O(max(a, b)) O(max(a,b))

辗转相除法近似为 O ( l o g ( a + b ) ) ) O(log(a + b))) O(log(a+b)))

//更相减损术
int gcd(int a, int b)
{
	if(a == b) return a;
	if(a > b) return gcd(a - b, b);
	if(a < b) return gcd(a, b - a);
}

//辗转相除法(欧几里得算法)
int gcd(int a, int b)
{
	return b ? gcd(b, a % b) : a;
}
欧拉函数

分解质因数法 O ( n ) O(\sqrt{n}) O(n )

Eratosthenes筛法 O ( n l o g n ) O(nlogn) O(nlogn)

线性筛法 O ( n ) O(n) O(n)

//分解质因数法(求 phi(n) )
int phi(int n)
{
	int ans = n;
	for (int i = 2; i * i <= n; 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;
}

//求 2 ~ n 中每个数的欧拉函数
//Eratosthenes筛法
void euler(int n)
{
	for (int i = 2; i <= n; i++)
	phi[i] = i;
	for (int i = 2; i <= n; i++)
	if (phi[i] == i)
	{
		for (int j = i; j <= n; j += i)
		phi[j] = phi[j] / i * (i - 1);
	}
}

//线性筛法
inline void euler(int n)
{
	memset(v, 0, sizeof v); //最小质因子
	m = 0; //质数数量
	for (int i = 2; i <= n; i++)
	{
		if (v[i] == 0)
		{
			v[i] = i;
			prime[++m] = i;
			phi[i] = i - 1;
		}
		//给当前的 i 乘上一个因子
		for (int j = 1; j <= m; j++)
		{
			// i 有比 prime[j] 更小的质因子,或者超出 n 的范围,停止循环
			if (prime[j] > v[i] || prime[j] > n / i) break;
			// prime[j] 是合数 i * prime[j] 的最小质因子
			v[i * prime[j]] = prime[j];
			phi[i * prime[j]] = phi[i] * (i % prime[j] ? prime[j] - 1 : prime[j]));
		}
	}
}
扩展欧几里得

O ( l o g n ) O(logn) O(logn)

a ∗ x ≡ 1 ( m o d a*x≡1(mod ax1(mod b ) b) b) 的最小整数解

a ∗ x + b ∗ y = 1 a * x + b * y = 1 ax+by=1

inline int exgcd(int a, int b, iny &x, int &y)
{
	if (!b)
	{
		x = 1;
		y = 0;
		return a;
	}
	int d = exgcd(a, b % a, x, y);
	int z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}
inline void work()
{
	scanf("%d%d", a, b);
	exgcd(a, b, x, y);
	printf("%d\n", (x % b + b) + b);
}
逆元
//快速幂法
ll Pow(ll x, ll y)
{
	ll res = 1;
	while (y)
	{
		if (y & 1) res = res * x % mod;
		y /= 2;
		x= x * x % mod;
	}
	return res;
}
inline ll inv(ll x)
{
	return Pow(x, mod - 2);
}

//扩欧
inline int exgcd(int a, int b, iny &x, int &y)
{
	if (!b)
	{
		x = 1;
		y = 0;
		return a;
	}
	int d = exgcd(a, b % a, x, y);
	int z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}
inline ll inv(ll a)
{
    ll x, y;
    exgcd(a, mod, x, y);
    return (x % mod + mod) % mod;
}

//线性
inv[1] = 1;
for (int i = 2; i <= n; i++)    
inv[i] = (p - p / i) * inv[p % i] % p;
中国剩余定理

O ( n l o g ( m o d ) ) O(nlog(mod)) O(nlog(mod))

求解同余方程组( m 1 , m 2 , . . . , m n m_1,m_2,...,m_n m1,m2,...,mn两两互质)

x ≡ a 1 ( m o d x≡a_1(mod xa1(mod m 1 ) m_1) m1)
x ≡ a 2 ( m o d x≡a_2(mod xa2(mod m 2 ) m_2) m2)
: : :
: : :
x ≡ a n ( m o d x≡a_n(mod xan(mod m n ) m_n) mn)

m m = ∏ i = 1 n m i mm = ∏_{i = 1}^{n}m_i mm=i=1nmi

m i = m m / m i mi = mm / m_i mi=mm/mi

t i t_i ti 为线性同余方程 m i ⋅ t i ≡ 1 ( m o d mi·t_i≡1(mod miti1(mod m i ) m_i) mi) 的一个解

方程组的解为 x = ∑ i = 1 n a i m i t i x = \sum_{i = 1}^{n} a_imit_i x=i=1naimiti

ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if (!b)
	{
		x = 1;
		y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, x, y);
	ll z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}
inline void work()
{
	sc(n);
	mm = 1;
	for (int i = 1; i <= n; i++)
	{
		sc(m[i]);
		sc(a[i]);
		mm *= m[i];
	}
	for (int i = 1; i <= n; i++)
	{
		ll mi = mm / m[i];
		ll x, y;
		ll d = exgcd(mi, m[i], x, y);
		ans = (ans + mi * x * a[i]) % mm;
	}
	printf("%lld\n", (ans + mm) % mm);
}
扩展中国剩余定理(不互质)

O ( n l o g n ) O(nlogn) O(nlogn)

m m = l c m ( m 1 , m 2 , . . . , m k − 1 ) mm = lcm(m_1, m_2,...,m_{k-1}) mm=lcm(m1,m2,...,mk1)

x + i ∗ m m x+i*mm x+imm是前 k − 1 k-1 k1个方程的通解

x + t ∗ m m ≡ a k ( m o d x+t*mm≡a_k(mod x+tmmak(mod m k ) m_k) mk)

等价于 m m ∗ t ≡ a k − x ( m o d mm*t≡a_k-x(mod mmtakx(mod m k ) m_k) mk)

则前 k k k 个方程的一个解为 x + t ∗ m x + t*m x+tm

ll exgcd(ll a, ll b, ll &x, ll &y)
{
	if (!b)
	{
		x = 1;
		y = 0;
		return a;
	}
	ll d = exgcd(b, a % b, x, y);
	ll z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}
ll CRT()
{
	ll mm = m[1];
	ll x = a[1], y;
	for (int i = 2; i <= n; i++)
	{
		a[i] -= x;
		ll xx = x;
		x = 0;
		y = 0;
		ll d = exgcd(mm, m[i], x, y);
		if (a[i] % d) return -1;
		x *= a[i] / d;
		ll c = m[i] / d;
		x = (x % c + c) % c;
		x = xx + x * mm;
		mm = mm * m[i] / d; 
		x = (x + mm) % mm;
	}
	return x;
}
Baby Step,Giant Step(大步小步)

O ( p ) O(\sqrt{p}) O(p )

求解高次同余方程

a x ≡ b ( m o d a^x≡b(mod axb(mod p ) p) p)

inline ll Pow(ll x, ll y)
{
	ll res = 1;
	while (y)
	{
		if (y & 1) res = res * x % p;
		y >>= 1;
		x = x * x % p;
	}
	return res;
}
int BSGS(int a, int b)
{
	map <int, int> hash;
	hash.clear();
	b %= p;
	int t = (int)sqrt(p) + 1;
	for (int j = 0; j < t; j++)
	{
		int val = (long long)b * Pow(a, j) % p;
		hash[val] = j;
	}
	a = Pow(a, t);
	if (a == 0) return b == 0 ? 1 : -1;
	for (int i = 0; i <= t; i++)
	{
		int val = Pow(a, i);
		int j = hash.find(val) == hash.end() ? -1 : hash[val];
		if (j >= 0 && i * t - j >= 0) return i * t - j;
	}
	return -1;
}
矩阵乘法

O ( l o g n ) O(logn) O(logn) n n n 为指数

//斐波那契数列
int k;
struct Xiao
{
	int sum[2][2];
	Xiao()
	{
		sum[0][0] = sum[0][1] = sum[1][0] = 1;
		sum[1][1] = 0;
	}
};
Xiao mul(Xiao x, Xiao y)
{
	Xiao a;
	for (int i = 0; i < 2; i++)
	for (int j = 0; j < 2; j++)
	{
		a.sum[i][j] = 0;
		for (int k = 0; k < 2; k++)
		a.sum[i][j] += x.sum[i][k] * y.sum[k][j];
		a.sum[i][j] %= 10000;
	}
	return a;
}
Xiao Pow(int x)
{
	Xiao a, b;
	a.sum[1][0] = a.sum[0][1] = 0;
	a.sum[1][1] = 1;
	while (x)
	{
		if (x % 2) a = mul(a, b);
		x /= 2;
		b = mul(b, b); 
	}
	return a;
}
inline void work()
{
	while (sc(k) && k != -1)
	{
		Xiao ans = Pow(k);
		printf("%d\n", ans.sum[1][0]);		
	}
}
高斯消元

O ( n 3 ) O(n^3) O(n3)

球形空间产生器

inline void work()
{
	sc(n);
	for (int i = 1; i <= n + 1; i++)
	{
		for (int j = 1; j <= n; j++)
		scanf("%lf", &a[i][j]);
	}
	for (int i = 1; i <= n; i++)
	for (int j = 1; j <= n; j++)
	{
		c[i][j] = 2 * (a[i][j] - a[i + 1][j]); //系数矩阵
		b[i] += a[i][j] * a[i][j] - a[i + 1][j] * a[i + 1][j]; //常数
	}
	//高斯消元
	for (int i = 1; i <= n; i++)
	{
		for (int j = i; j <= n; j++) //找到 x[i] 的系数不为 0 的一个方程
		{
			if (fabs(c[j][i]) > 1e-8)
			{
				for (int k = 1; k <= n; k++)
				swap(c[i][k], c[j][k]);
				swap(b[i], b[j]);
			}
		}
		for (int j = 1; j <= n; j++) //消去其他方程的 x[i] 的系数
		{
			if (i == j) continue;
			double rate = c[j][i] / c[i][i];
			for (int k = i; k <= n; k++)
			c[j][k] -= c[i][k] * rate;
			b[j] -= b[i] * rate;
		}
	}
	for (int i = 1; i < n; i++)
	printf("%.3lf ", b[i] / c[i][i]);
	printf("%.3lf\n", b[n] / c[n][n]);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值