见识
四方定理:所有自然数至多只要用四个数的平方和就可以表示。
费马定理:当整数n >2时,关于x, y, z的方程 x^n + y^n = z^n 没有正整数解。
顺序完全N叉树求先祖:a = (a + n - 2) / n。
同余定理:给定一个正整数m,如果两个整数a和b满足a-b能够被m整除,即(a-b)/m得到一个整数,那么就称整数a与b对模m同余,记作a≡b(mod m)。对模m同余是整数的一个等价关系。
威尔逊定理:若p为质数,则p可整除(p-1)!+1。
如:7为质数,则7可整除(7 - 1)! + 1 = 721,即721 % 7 == 0
欧拉函数:对正整数n,欧拉函数是小于n的正整数中与n互质的数的数目(φ(1)=1)例如φ(8)=4,因为1,3,5,7均和8互质。
欧拉定理:若n,a为正整数,且n,a互素,即gcd(a,n) = 1,则a^φ(n) ≡ 1 (mod n), 其中φ(n)为欧拉函数。
如:n = 5, a = 7. 因为与5互质的有1、2、3、4,即φ(5) = 4,则(7 ^ 4) % 5 = 2401 % 5 = 1。
三角形半周长 P=(a+b+c)/2,面积sqrt(P(P-a)(P-b)(P-c)),中线 Ma=sqrt(2(b^2+c^2)-a^2)/2。
数据规模较小时求解,数据规模较大时特判。设L,K为任意自然数,L!=2时在[L,L+2K)区间内必不可能有超过K个素数。L=2时,也只有K=1,2,3时有超过K个素数。总结:遇到素数题不求素数才是基操。
求最小值时注意下限要大于0。
当109级出现乘法,必开long long 。牺牲精度的double范围比long long还大,可解决±261左右规模问题。
三个变量之间存在关系,其中一个由输入确定,必优化成单层循环。
素数筛法
int sqrt_n = sqrt(b); is_prime[1] = 0; for (i = 2; i <= b; i++) is_prime[i] = 1; for (i = 2; i < sqrt_n; i++) { if (is_prime[i]) for (j = i * i; j <= b; j += i) is_prime[j] = 0; }
卢卡斯定理:利用模运算快速求出二项式系数C(n,r),适用于不用模运算就无法求出其结果的、具有非常大的n和r的二项式系数。
LL PowMod(LL a, LL b, LL MOD) { //快速幂 LL ret = 1; while (b) { if (b & 1) ret = (ret * a) % MOD; a = (a * a) % MOD; b >>= 1; } return ret; } LL fac[100005]; LL Get_Fact(LL p) { //初始化 fac[0] = 1; for (int i = 1; i <= p; i++) fac[i] = (fac[i - 1] * i) % p; } LL Lucas(LL n, LL m, LL p) { //Lucas 定理 LL ret = 1; while (n && m) { LL a = n % p, b = m % p; if (a < b) return 0; ret = (ret * fac[a] * PowMod(fac[b] * fac[a - b] % p, p - 2, p)) % p; n /= p; m /= p; } return ret; }
卡特兰数(Catalan number)是 组合数学 中一个常出现在各种 计数问题 中的 数列。
数列的前几项为:1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862,...
题目描述:
n 个元素进栈序列为:1,2,3,4,...,n,则有多少种出栈序列。
思路:
我们将进栈表示为 +1,出栈表示为 -1,则 1 3 2 的出栈序列可以表示为:+1 -1 +1 +1 -1 -1。
假设非法序列为 A,对应的序列为 B。每个 A 只有一个"第一个前缀和小于 0 的前缀",所以每个 A 只能产生一个 B。而每个 B 想要还原到 A,就需要找到"第一个前缀和大于 0 的前缀",显然 B 也只能产生一个 A。
#include <cstdio> using namespace std; long long catalan[1000005]; int main() { int n; scanf("%d", &n); catalan[0] = catalan[1] = 1; for (int i = 2; i <= n; i++) for (int j = 0; j <= i - 1; j++) catalan[i] += catalan[j] * catalan[i - j - 1]; printf("%lld\n", catalan[n]); return 0; }
一段连续自然数异或结果
#include<bits/stdc++.h> using namespace std; #define md 1000000007 int yh (int n, int m) { if (abs (n - m) < 4) { int n0 = min (n, m); int n1, n2, n3; if (abs (n - m) < 1) n1 = 0; else n1 = n0 + 1; if (abs (n - m) < 2) n2 = 0; else n2 = n0 + 2; if (abs (n - m) < 3) n3 = 0; else n3 = n0 + 3; return (n0 ^ n1) ^ (n2 ^ n3); } return yh (n - 1 - (n - 1) % 4, n - 1) ^yh (m - m % 4, m); } int main() { int t; long long int ans = 0; scanf ("%d", &t); while (t--) { int n, m; scanf ("%d %d", &n, &m); ans += yh (n, m) % md; ans %= md; } printf ("%d", ans); return 0; }