这部分开始,对算法与数学中的一些问题进行探讨 
包括数论问题,FFT(快速傅立叶变换),FWT(快速沃尔什变换) 
莫比乌斯反演,surreal number,杜教筛等等
 
质数 
质数的判定 
1 2 3 4 5 6 7 bool isPrime(int x) {     if (x < 2) return  false ;     for (int i = 2; i <= sqrt(x); i++) {         if (x % i == 0) return  false ;     }     return  true ; } 
 
Eratosthenes筛法 
for   ∀ x ∈ [ 2 ⋯ n ] \textbf{for} \ \forall x\in [2\cdots n] for   ∀ x ∈ [ 2 ⋯ n ]  
用 v[...] 数组来标记合数 \quad \text{用 v[...] 数组来标记合数} 用  v[...]  数组来标记合数  
if   v [ x ] = 1 , x  是合数 \quad \textbf{if} \ v[x]=1, x \text{ 是合数} if   v [ x ] = 1 , x   是合数  
if   v [ x ] = 0 , x  是质数 \quad \textbf{if} \ v[x]=0, x \text{ 是质数} if   v [ x ] = 0 , x   是质数  
x 2 , ( x + 1 ) ⋅ x , ⋯   , ⌊ n / x ⌋ ⋅ x   都标记成为合数 \quad \quad x^2, (x+1) \cdot x, \cdots, \lfloor n/x \rfloor \cdot x \ \textbf{都标记成为合数} x 2 , ( x + 1 ) ⋅ x , ⋯ , ⌊ n / x ⌋ ⋅ x   都标记成为合数 
1 2 3 4 5 6 7 8 9 10 11 const int maxn = 1e6 + 5; int v[maxn]; void primes(int n) {     memset(v, 0, sizeof(v));     for (int i = 2; i <= n; i++) {         if (v[i]) continue ;         printf ("%d\n" , i);         for (int j = i; j <= n/i; j++) v[i*j] = 1;     } } 
 
线性筛法 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const int maxn = 1e6 + 10; int v[maxn], prime[maxn]; int primes(int n) {     memset(v, 0, sizeof(v));     int 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 (v[i] < prime[j] || i * prime[j] > n) break ;             v[i*prime[j]] = prime[j];         }     }     return  m; } int main  () {     int n = 1e5;     int m = primes(n);     for (int i = 1; i <= m; i++) printf ("%d\n" , prime[i]); } 
 
质数算法实践 
ZOJ1842 
需要用到一个性质,任意合数 x x x  ,必然有一个 ⩽ x \leqslant \sqrt{x} ⩽ x    的质因子
用筛法筛出 [ 2 , R ] [2, \sqrt{R}] [ 2 , R  ]   之间所有的质数 
for   ∀ p ∈ p r i m e s [ . . . ] \textbf{for} \ \forall p \in primes[...] for   ∀ p ∈ p r i m e s [ . . . ]  
       ~~~~~~             for   ∀ i ∈ ⌊ L / p ⌋ ⋯ ⌊ R / p ⌋ v [ i × p ] = 1 \textbf{for} \ \forall i \in \lfloor L/p \rfloor \cdots \lfloor R/p \rfloor \quad v[i \times p] = 1 for   ∀ i ∈ ⌊ L / p ⌋ ⋯ ⌊ R / p ⌋ v [ i × p ] = 1   标记合数 
线性扫描 [ L , R ] [L,R] [ L , R ]   ,得到所有质数,并且计算最短距离 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 const int maxn = 1e5 + 10; const ll inf = 0x3f3f3f3f3f3f3f3f; ll L, R; void primes(ll n, vector<ll>& vec) {     bool v[maxn];     memset(v, 0, sizeof(v));     for (ll i = 2; i <= n; i++) {         if (v[i]) continue ;         vec.push_back(i);         for (ll j = i; j < n/i; j++) v[i*j] = 1;     } } void solve  () {     vector<ll> vec;     primes(sqrt(R), vec);     unordered_map<ll, int> fl;     for (auto p : vec) {         for (ll i = (L)/p; i <= (R)/p; i++) if (i > 1) fl[i*p] = 1;     }     vector<ll> res;     for (ll i = max(2ll, L); i <= R; i++) if (fl[i] == 0) res.push_back(i);     if (res.size() < 2) printf ("There are no adjacent primes.\n" );     else  {         ll ans1 = -inf, ans2 = inf;         ll a, b, c, d;         for (int i = 0; i < res.size()-1; i++) {             if (chmax(ans1, res[i+1] - res[i])) c = res[i], d = res[i+1];             if (chmin(ans2, res[i+1] - res[i])) a = res[i], b = res[i+1];         }         printf ("%lld,%lld are closest, %lld,%lld are most distant.\n" , a, b, c, d);     } } void init  () {     // } int main  () {     //freopen("input.txt" , "r" , stdin);     while  (scanf("%lld%lld" , &L, &R) == 2) {         init();         solve();     } } 
 
补充:上取整和下取整 
⌈ a / b ⌉ \lceil a/b \rceil ⌈ a / b ⌉ 
 
⌊ a / b ⌋ \lfloor a/b \rfloor ⌊ a / b ⌋ 
 
( a / b ) (a/b) ( a / b )   四舍五入 
 
质因数分解 
 
UVA10780  
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 const int maxn = 1e5 + 10; const int inf = 0x3f3f3f3f; int m, n; class A { public:     int p, e;     A() = default;     A(int p) : p(p) {         e = 0;     } }; bool fl[maxn]; vector<A> primes; void divide(int n, vector<A>& primes) {     primes.clear();     for (int i = 2; i <= sqrt(n); i++) {         if  (n % i == 0) {             primes.push_back(A(i));             while  (n % i == 0) n /= i, primes.back().e++;         }     }     if  (n > 1) {         primes.push_back(n);         primes.back().e = 1;     } } void solve(const vector<A>& primes) {     int ans = inf;     for (const auto& p : primes) {         int e2 = 0;         for (int x = n; x; x /= p.p) e2 += x/p.p;         ans = min(ans, e2 / p.e);     }     if (ans == inf || ans == 0) printf ("Impossible to divide\n" );     else  printf ("%d\n" , ans); } int main  () {     freopen("input.txt" , "r" , stdin);     int kase;     scanf("%d" , &kase);     int T = 0;     while  (kase--) {         //init();         scanf("%d%d" , &m, &n);         printf ("Case %d:\n" , ++T);         divide(m, primes);         // then  solve         solve(primes);     } } 
 
质因数分解实践 
N = p 1 c 1 ⋅ p 2 c 2 ⋯ p m c m = a 1 ⋅ a 2 ⋯ a m \begin{gathered}
N = p_1^{c_1} \cdot p_2^{c_2} \cdots p_m^{c_m} \\
= a_1 \cdot a_2 \cdots a_m
\end{gathered}
 N = p 1 c 1   ⋅ p 2 c 2   ⋯ p m c m   = a 1  ⋅ a 2  ⋯ a m   
下面证明一个结论 
a 1 a 2 ⋯ a m ⩾ a 1 + a 2 + ⋯ a m a_1a_2\cdots a_m \geqslant a_1 +a_2 + \cdots a_m a 1  a 2  ⋯ a m  ⩾ a 1  + a 2  + ⋯ a m  
这个结论比较好证明,假设两个数 a , b a, b a , b  
要证明 a b ⩾ a + b ab \geqslant a+b a b ⩾ a + b  
不妨设 b > a , b = a + m b>a, \quad b = a + m b > a , b = a + m  
a b = a 2 + a m , a + b = 2 a + m ab=a^2+am, \quad a+b = 2a+m a b = a 2 + a m , a + b = 2 a + m  
a b − ( a + b ) = a ( a − 2 ) + ( a + 1 ) m ⩾ 0 ab - (a+b) = a(a-2) + (a+1)m \geqslant 0 a b − ( a + b ) = a ( a − 2 ) + ( a + 1 ) m ⩾ 0 
根据数学归纳法,原结论成立
下面我们运用这个结论来解决一个问题 
EOlymp1246 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 inline int divide(int& n, int d) {     int ans = 1;     while  (n % d == 0) {         ans *= d;         n /= d;     }     return  ans; } ll solve(int n) {     if (n == 1) return  2;     ll ans = 0;     int cnt = 0;     _rep(i, 2, sqrt(n)) {         if (n % i) continue ;         cnt++;         ll x = 1ll * divide(n, i);         ans += x;     }     if (n > 1) {         cnt++;         ans += n;     }     if (cnt <= 1) ans++;     return  ans; } int main  () {     freopen("input.txt" , "r" , stdin);     int n, kase = 0;     while  (scanf("%d" , &n) == 1 && n) {         printf ("Case %d: " , ++kase);         // then  solve         ll ans = solve(n);         printf ("%lld\n" , ans);     } } 
 
阶乘分解 
先来看一个结论 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 const int maxn = 1e6 + 10; int n; vector<int> primes; int fl[maxn]; void prework  () {     //debug(n);     _rep(i, 2, n) {         if (fl[i]) continue ;         primes.push_back(i);         for (int j = i; j <= n/i; j++) fl[i*j] = 1;     } } void solve  () {     for (auto p : primes) {         //debug(p);         int ans = 0;         for (int x = n; x; x /= p) ans += x/p;         printf ("%d %d\n" , p, ans);     }     return ; } void init  () {     memset(fl, 0, sizeof(fl));     primes.clear(); } int main  () {     freopen("input.txt" , "r" , stdin);     init();     cin >> n;     // then  solve     prework();     solve(); } 
 
阶乘分解计算组合数 
ZOJ1863 
组合数算法,在数学问题中经常出现 
这里我们把一些常用的函数给封装起来
 
表示对结果 ( n ! ) d (n!)^d ( n ! ) d   进行阶乘分解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 const int maxn = 1e5 + 10; const int N = 1e5; int p, q, r, s; class A { public:     int p, e;     A  () {}     A(int p) : p(p) {         e = 0;     } }; bool fl[maxn]; vector<A> primes; void prework  () {     memset(fl, 0, sizeof(fl));     _rep(i, 2, N) {         if (fl[i]) continue ;         primes.push_back(A(i));         for (int j = i; j <= N/i; j++) fl[i*j] = 1;     } } void factorial(int n, int d) {     for (auto& p : primes) {         for (int x = n; x; x /= p.p) p.e += d*(x/p.p);     } } void init  () {     for (auto& p : primes) p.e = 0; } void solve  () {     init();     factorial(p, 1);     factorial(q, -1);     factorial(p-q, -1);     factorial(r, -1);     factorial(s, 1);     factorial(r-s, 1);     double ans = 1;     for (auto p : primes) {         ans *= pow(p.p, p.e);     }     printf ("%.5lf\n" , ans); } int main  () {     freopen("input.txt" , "r" , stdin);     prework();     while  (cin >> p >> q >> r >> s) {         // then  solve         solve();     } }