对顶数据结构 
始终在序列中间的某个指定位置进行操作  
此类问题经常用对顶数据结构  
对顶数据结构常用的有“对顶栈,对顶堆”
HDU4699  
具体数学:递归模型 
Hanoi塔 
三根柱子的 Hanoi 塔模型的递归解为
T n = 2 T n − 1 + 1 T_n = 2T_{n-1} + 1
 T n  = 2 T n − 1  + 1 
直线分割模型 
平面上的 n n n   条直线所界定的区域的最大个数 L n L_n L n   
即最多能把平面分割成几部分? 
直线分割模型拓展(一)—— 任意直线线段组合图形,比如 Z Z Z   字形
Z n = Z n − 1 + p ⋅ ( n − 1 ) + 1 Z_n = Z_{n-1} + p\cdot (n-1) + 1
 Z n  = Z n − 1  + p ⋅ ( n − 1 ) + 1 
其中 , p p p   表示两个图形做多能够产生的交点数 
如果是 V V V   字形,此时 p = 4 p = 4 p = 4  ,因为两个 V V V   字形最多产生 4 4 4   个交点
 
直线分割模型拓展 (二) —— 三维区域 
比如在一块厚奶酪上,划出 k k k   道切痕,问最多能得到多少块奶酪 
P n P_n P n    表示 n n n   个不同平面能够界定的三维区域最大个数 
 
P n = P n − 1 + L n − 1 P_n = P_{n-1} + L_{n-1}
 P n  = P n − 1  + L n − 1  
其中 L n L_{n} L n    表示平面上的 n n n   条直线能够界定的区域最大个数 
 
 
 
约瑟夫问题 
{ J ( 1 ) = 1 J ( 2 n ) = 2 J ( n ) − 1 n ⩾ 1 J ( 2 n + 1 ) = 2 J ( n ) + 1 n ⩾ 1 \begin{cases}
J(1) = 1 \\
J(2n) = 2J(n) - 1 && n \geqslant 1 \\
J(2n+1) = 2J(n) + 1 && n \geqslant 1
\end{cases}
 ⎩ ⎪ ⎪ ⎨ ⎪ ⎪ ⎧  J ( 1 ) = 1 J ( 2 n ) = 2 J ( n ) − 1 J ( 2 n + 1 ) = 2 J ( n ) + 1   n ⩾ 1 n ⩾ 1  
递归式的封闭形式 n = 2 m + l n = 2^m + l n = 2 m + l 
J ( 2 m + l ) = 2 l + 1 , m ⩾ 0 ,   0 ⩽ l < 2 m J(2^m+l) = 2l+1, \quad m \geqslant 0, \ 0 \leqslant l < 2^m
 J ( 2 m + l ) = 2 l + 1 , m ⩾ 0 ,   0 ⩽ l < 2 m 
注意到如果 2 m ⩽ n < 2 m + 1 2^m \leqslant n < 2^{m+1} 2 m ⩽ n < 2 m + 1  ,实际上 l = n   m o d   2 m l = n \bmod 2^m l = n m o d 2 m  ,0 ⩽ l < 2 m 0 \leqslant l < 2^m 0 ⩽ l < 2 m  
 
 
循环移位 
如果将 n n n   写成二进制形式,n = ( b m b m − 1 ⋯ b 1 b 0 ) 2 ,   l = n   m o d   2 m n = (b_mb_{m-1}\cdots b_1b_0)_2, \ l = n \bmod 2^m n = ( b m  b m − 1  ⋯ b 1  b 0  ) 2  ,   l = n m o d 2 m 
l = ( b m − 1 b m − 2 ⋯ b 1 b 0 ) 2 2 l = ( b m − 1 b m − 2 ⋯ b 1 b 0 0 ) 2 2 l + 1 = ( b m − 1 b m − 2 ⋯ b 1 b 0 1 ) 2 , b m = 1 J ( n ) = 2 l + 1 = ( b m − 1 b m − 2 ⋯ b 1 b 0 b m ) 2 \begin{gathered}
l = (b_{m-1}b_{m-2}\cdots b_1b_0)_2 \\
2l = (b_{m-1}b_{m-2}\cdots b_1b_00)_2 \\
2l + 1 = (b_{m-1}b_{m-2}\cdots b_1b_01)_2 , \quad b_m = 1 \\
J(n) = 2l+1 = (b_{m-1}b_{m-2}\cdots b_1b_0b_m)_2
\end{gathered}
 l = ( b m − 1  b m − 2  ⋯ b 1  b 0  ) 2  2 l = ( b m − 1  b m − 2  ⋯ b 1  b 0  0 ) 2  2 l + 1 = ( b m − 1  b m − 2  ⋯ b 1  b 0  1 ) 2  , b m  = 1 J ( n ) = 2 l + 1 = ( b m − 1  b m − 2  ⋯ b 1  b 0  b m  ) 2   
 
J ( n ) J(n) J ( n )   作用于 n n n  ,实际上是相当于将 n n n   的二进制环形循环左移  1 1 1   位 
如果遇到前导 0 0 0   则扔掉,如此执行若干次 
( J ( J ⋯ J ( n ) ⋯   ) ) = 2 V ( n ) − 1 V ( n ) 表示 n 中有几个为 1 的位 \begin{gathered}
(J(J\cdots J(n) \cdots )) = 2^{V(n)} - 1 \\
V(n) \text{表示} n \text{中有几个为} 1 \text{的位}
\end{gathered}
 ( J ( J ⋯ J ( n ) ⋯ ) ) = 2 V ( n ) − 1 V ( n ) 表示 n 中有几个为 1 的位  
特别地,如果有 J ( n ) = n / 2 J(n) = n/2 J ( n ) = n / 2  ,那么 n n n   循环左移 1 1 1   位(舍弃前导0)与循环右移 1 1 1   位的结果相等1 2 n/2 = n >> 1 J(n) = n 循环左移 1 位 
 
 
 
 
 
成套方法 
成套方法简介 
递归式
f ( 1 ) = α f ( 2 n ) = 2 f ( n ) + β n ⩾ 1 f ( 2 n + 1 ) = 2 f ( n ) + γ n ⩾ 1 \begin{gathered}
f(1) = \alpha \\
f(2n) = 2f(n) + \beta && n \geqslant 1 \\
f(2n+1) = 2f(n) + \gamma && n \geqslant 1
\end{gathered}
 f ( 1 ) = α f ( 2 n ) = 2 f ( n ) + β f ( 2 n + 1 ) = 2 f ( n ) + γ   n ⩾ 1 n ⩾ 1  
根据枚举猜想,最后可以表示成形式 
f ( n ) = A ( n ) α + B ( n ) β + C ( n ) γ f(n) = A(n)\alpha + B(n)\beta +C(n) \gamma
 f ( n ) = A ( n ) α + B ( n ) β + C ( n ) γ 
如果令 n = 2 m + l n = 2^m + l n = 2 m + l  ,此时有 0 ⩽ l < 2 m   ( n ⩾ 1 ) 0 \leqslant l < 2^m \ (n \geqslant 1) 0 ⩽ l < 2 m   ( n ⩾ 1 ) 
A ( n ) = 2 m B ( n ) = 2 m − 1 − l C ( n ) = l \begin{gathered}
A(n) = 2^m \\
B(n) = 2^m - 1 - l \\
C(n) = l
\end{gathered}
 A ( n ) = 2 m B ( n ) = 2 m − 1 − l C ( n ) = l  
检验任意特殊值  α = 1 , β = γ = 0 , ⟹ f ( n ) = A ( n ) \alpha = 1, \beta = \gamma = 0, \Longrightarrow f(n) = A(n) α = 1 , β = γ = 0 , ⟹ f ( n ) = A ( n ) 
A ( 1 ) = 1 A ( 2 n ) = 2 A ( n ) n ⩾ 1 A ( 2 n + 1 ) = 2 A ( n ) n ⩾ 1 \begin{gathered}
A(1) = 1 \\
A(2n) = 2A(n) && n \geqslant 1 \\
A(2n+1) = 2A(n) && n \geqslant 1 \\
\end{gathered}
 A ( 1 ) = 1 A ( 2 n ) = 2 A ( n ) A ( 2 n + 1 ) = 2 A ( n )   n ⩾ 1 n ⩾ 1  
而上面猜想说 A ( n ) = 2 m A(n) = 2^m A ( n ) = 2 m   是否正确? 
A ( 2 m + 1 + 2 l ) ⟹ 对m归纳 , 0 ⩽ 2 l < 2 m + 1 A\left(2^{m+1}+2 l\right) \Longrightarrow \text{对m归纳}, 0 \leqslant 2l < 2^{m+1} A ( 2 m + 1 + 2 l ) ⟹ 对 m 归纳 , 0 ⩽ 2 l < 2 m + 1  
A ( 2 m + 1 + 2 l ) = 2 m + 1 A\left(2^{m+1}+2 l\right) = 2^{m+1} A ( 2 m + 1 + 2 l ) = 2 m + 1  
A ( 2 m + 1 + 2 l ) = 2 A ( 2 m + l ) = 2 ⋅ 2 m = 2 m + 1 A\left(2^{m+1}+2 l\right) = 2A(2^m + l) = 2\cdot 2^m = 2^{m+1} A ( 2 m + 1 + 2 l ) = 2 A ( 2 m + l ) = 2 ⋅ 2 m = 2 m + 1  
猜想正确
成套方法步骤 
成套方法一般取特殊的函数值来求解
取 f ( n ) = 1 f(n) = 1 f ( n ) = 1   常值函数
1 = α 1 = 2 + β ⇒ β = − 1 1 = 2 + γ ⇒ γ = − 1 \begin{gathered}
1 = \alpha \\
1 = 2 + \beta && \Rightarrow \beta = -1 \\
1 = 2 + \gamma && \Rightarrow \gamma = -1 
\end{gathered}
 1 = α 1 = 2 + β 1 = 2 + γ   ⇒ β = − 1 ⇒ γ = − 1  
由此,可以推出 
A ( n ) − B ( n ) − C ( n ) = f ( n ) = 1 A(n)-B(n)-C(n) = f(n)=1 A ( n ) − B ( n ) − C ( n ) = f ( n ) = 1 
 
取 f ( n ) = n f(n) = n f ( n ) = n   不动点
1 = α 2 n = 2 n + β ⇒ β = 0 2 n + 1 = 2 n + γ ⇒ γ = 1 \begin{gathered}
1 = \alpha \\
2n = 2n + \beta && \Rightarrow \beta = 0 \\
2n+1 = 2n + \gamma && \Rightarrow \gamma = 1
\end{gathered}
 1 = α 2 n = 2 n + β 2 n + 1 = 2 n + γ   ⇒ β = 0 ⇒ γ = 1  
由此,可以推出 
A ( n ) + C ( n ) = n A(n)+C(n) = n A ( n ) + C ( n ) = n 
 
综上所述
A ( n ) = 2 m n = 2 m + l   a n d   0 ⩽ l < 2 m A ( n ) − B ( n ) − C ( n ) = 1 A ( n ) + C ( n ) = n \begin{gathered}
A(n) = 2^m && n = 2^m+l \ \bold{and} \ 0 \leqslant l < 2^m \\
A(n)-B(n)-C(n) = 1 \\
A(n) + C(n) = n
\end{gathered}
 A ( n ) = 2 m A ( n ) − B ( n ) − C ( n ) = 1 A ( n ) + C ( n ) = n  n = 2 m + l   a n d   0 ⩽ l < 2 m 
 
 
递归式与基变换 
对递归式问题进行推广,对于递归式
f ( j ) = a j 1 ⩽ j < d f ( d n + j ) = c f ( n ) + β j 0 ⩽ j < d ,   n ⩾ 1 \begin{gathered}
f(j) = a_j && 1 \leqslant j < d \\
f(dn+j) = cf(n) + \beta_j && 0 \leqslant j < d, \ n \geqslant 1
\end{gathered}
 f ( j ) = a j  f ( d n + j ) = c f ( n ) + β j    1 ⩽ j < d 0 ⩽ j < d ,   n ⩾ 1  
根据基数与进制分解的原理 ,变动基数的解可以表示如下
f ( ( b m b m − 1 ⋯ b 1 b 0 ) d ) = ( α b m β b m − 1 β b m − 2 ⋯ β b 1 β b 0 ) c f\left( (b_mb_{m-1}\cdots b_1b_0)_d \right) = (\alpha_{b_m} \beta_{b_{m-1}} \beta_{b_{m-2}} \cdots \beta_{b_1}\beta_{b_0})_c
 f ( ( b m  b m − 1  ⋯ b 1  b 0  ) d  ) = ( α b m   β b m − 1   β b m − 2   ⋯ β b 1   β b 0   ) c  
例如给定递归式
f ( 1 ) = 34 f ( 2 ) = 5 f ( 3 n ) = 10 f ( n ) + 76 n ⩾ 1 f ( 3 n + 1 ) = 10 f ( n ) − 2 n ⩾ 1 f ( 3 n + 2 ) = 10 f ( n ) + 8 n ⩾ 1 \begin{gathered}
f(1) = 34 \\
f(2) = 5 \\
f(3n) = 10f(n) + 76 && n \geqslant 1 \\
f(3n+1) = 10f(n)-2 && n \geqslant 1 \\
f(3n+2) = 10f(n)+8 && n \geqslant 1
\end{gathered}
 f ( 1 ) = 3 4 f ( 2 ) = 5 f ( 3 n ) = 1 0 f ( n ) + 7 6 f ( 3 n + 1 ) = 1 0 f ( n ) − 2 f ( 3 n + 2 ) = 1 0 f ( n ) + 8   n ⩾ 1 n ⩾ 1 n ⩾ 1  
计算 f ( 19 ) f(19) f ( 1 9 )  ,注意到 19 = ( 201 ) 3 19 = (201)_3 1 9 = ( 2 0 1 ) 3  
f ( 19 ) = f ( ( 201 ) 3 ) = ( α 2   β 0   β 1 ) 10 = ( 5   76   − 2 ) 10 = 1258 \begin{gathered}
f(19) = f((201)_3) = (\alpha_2 \ \beta_0 \ \beta_1)_{10} \\
= (5 \ 76 \ -2)_{10} = 1258
\end{gathered}
 f ( 1 9 ) = f ( ( 2 0 1 ) 3  ) = ( α 2    β 0    β 1  ) 1 0  = ( 5   7 6   − 2 ) 1 0  = 1 2 5 8  
约瑟夫问题扩展 
任意位置 
UVALive3882  
约瑟夫问题推广 
Josephus问题的一些结论 
约瑟夫发现自己处在给定位置  j j j  ,并且他有一次机会来指定淘汰参数 q q q  
使得每 q − 1 q-1 q − 1   个人处死一人,问他能否保全自己
先来看 Josephus 方程的递推形式
f ( 1 ) = 0 f ( n ) = ( f ( n − 1 ) + q )   m o d   n \begin{gathered}
f(1) = 0 \\
f(n) = (f(n-1) + q) \bmod n
\end{gathered}
 f ( 1 ) = 0 f ( n ) = ( f ( n − 1 ) + q ) m o d n  
其中,f ( n ) f(n) f ( n )   表示当前有 n n n   个人 
从初始位置 0 0 0   开始 (0 0 0   位置不删除) 
最后幸存者的编号是 f ( n ) f(n) f ( n )  
特殊计数序列——Catalan数 
定理  考虑由 n n n   个 + 1 +1 + 1   和 n n n   个 − 1 -1 − 1   组成的 2 n 2n 2 n   项序列
a 1 , a 2 , ⋯   , a 2 n a_1, a_2, \cdots , a_{2n}
 a 1  , a 2  , ⋯ , a 2 n  
其部分和总是满足 
a 1 + a 2 + ⋯ + a k ⩾ 0 ( ∀ k = { 1 , 2 , ⋯   , 2 n } ) a_1+a_2+\cdots + a_k \geqslant 0 \quad (\forall k = \{1, 2, \cdots, 2n \})
 a 1  + a 2  + ⋯ + a k  ⩾ 0 ( ∀ k = { 1 , 2 , ⋯ , 2 n } ) 
这种序列的个数等于第 n n n   个 Catalan 数
C n = 1 n + 1 ( 2 n n ) ( n ⩾ 0 ) C_n = \frac{1}{n+1} {2n \choose n} (n \geqslant 0)
 C n  = n + 1 1  ( n 2 n  ) ( n ⩾ 0 ) 
证明如下 
通过以上证明了任意不可接受序列 U ( n , n ) U(n, n) U ( n , n )   与序列 C ( n + 1 , n − 1 ) C(n+1, n-1) C ( n + 1 , n − 1 )   存在对应关系 
C ( n + 1 , n − 1 ) C(n+1, n-1) C ( n + 1 , n − 1 )   的个数实际上就是排列数
( 2 n ) ! ( n + 1 ) ! ( n − 1 ) ! \frac{(2n)!}{(n+1)!(n-1)!}
 ( n + 1 ) ! ( n − 1 ) ! ( 2 n ) !  
从而
U ( n ) = ( 2 n ) ! ( n + 1 ) ! ( n − 1 ) ! U(n) = \frac{(2n)!}{(n+1)!(n-1)!}
 U ( n ) = ( n + 1 ) ! ( n − 1 ) ! ( 2 n ) !  
A ( n ) = ( 2 n n ) − U ( n ) = 1 n + 1 ( 2 n n ) A(n) = {2n \choose n} - U(n) = \frac{1}{n+1}{2n \choose n}
 A ( n ) = ( n 2 n  ) − U ( n ) = n + 1 1  ( n 2 n  ) 
计数类问题编程实现常用函数 
阶乘分解 
 
对于 N ! N! N !   进行阶乘分解的结果是
∑ p k ⩽ N ⌊ N p k ⌋ \sum_{p^k \leqslant N} \lfloor \frac{N}{p_k} \rfloor
 p k ⩽ N ∑  ⌊ p k  N  ⌋ 
试除法分解质因数 
1 2 3 4 5 6 7 8 9 10 11 12 void divide(int x) {     for  (int i = 2; i <= x/i; i++) {         if  (x % i == 0) {             int s = 0;             while  (x % i == 0) s++, x /= i;             // i^s             make_pair(i, s);         }     }     if  (x > 1) make_pair(x, 1);     // x^1 } 
 
朴素筛法求质数 
1 2 3 4 5 6 7 8 9 10 11 vector<int> primes; bool st[maxn]; // init st[...] = 0 // st = true  表示这个数是合数 void get_primes(int n) {     for  (int i = 2; i <= n; i++) {         if  (st[i]) continue ;         primes.push_back(i);         for  (int j = 2*i; j <= n; j += i) st[j] = true ;     } } 
 
线性筛法求质数 
1 2 3 4 5 6 7 8 9 10 11 12 vector<int> primes; bool st[maxn]; void get_primes  () {     for  (int i = 2; i <= n; i++) {         if  (!st[i]) primes.push_back(i);         for  (int j = 0; primes[j] <= n/i; j++) {             st[primes[j] * i] = true ;             if  (i % primes[j]) break ;         }     } } 
 
Catalan 数经典应用 
这里涉及到一个编程技巧,叫高精度压位  
Acwing130 
其实就是计算 Catalan 数
1 n + 1 ( 2 n n ) \frac{1}{n+1} {2n \choose n}
 n + 1 1  ( n 2 n  ) 
algorithm 
打表 [ 2 , 2 n ] [2, 2n] [ 2 , 2 n ]   所有的素数 
阶乘分解,f o r   ∀ p ∈ p r i m e s [ ⋯   ] \bold{for} \ \forall p \in \bold{primes}[\cdots] f o r   ∀ p ∈ p r i m e s [ ⋯ ]  
求出 p w [ p ] = g e t ( 2 n , p ) − 2 ⋅ g e t ( n , p ) \bold{pw}[p]= \bold{get}(2n, p) - 2\cdot \bold{get}(n, p) p w [ p ] = g e t ( 2 n , p ) − 2 ⋅ g e t ( n , p )  
即素数 p p p   在( 2 n n ) 2n \choose n ( n 2 n  )   这项中的幂指 
对 n + 1 n+1 n + 1   进行素因子分解,n + 1 = ⋯ p s ⋯ n+1 = \cdots p^s \cdots n + 1 = ⋯ p s ⋯  ,然后 p w [ p ] − = s \bold{pw}[p] -= s p w [ p ] − = s  
f o r   ∀ p ∈ p r i m e s [ ⋯   ] : \bold{for} \ \forall p \in \bold{primes}[\cdots]: f o r   ∀ p ∈ p r i m e s [ ⋯ ] :   执行 p w [ p ] \bold{pw}[p] p w [ p ]   次 m u t i ( a n s , p ) \bold{muti}(ans, p) m u t i ( a n s , p )  
 
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 65 66 67 68 69 70 71 72 const int maxn = 120000 + 10; int n; vector<int> primes; bool st[maxn]; void get_primes  () {     memset(st, 0, sizeof st);     for  (int i = 2; i <= 2*n; i++) {         if  (st[i]) continue ;         primes.push_back(i);         for  (int j = 2*i; j <= 2*n; j += i) st[j] = true ;     } } int pw[maxn]; inline int get(int n, int p) {     int s = 0;     while  (n) s += n/p, n /= p;     return  s; } void multi(vector<ll>& res, int b) {     ll t = 0;     for  (int i = 0; i < res.size(); i++) {         t += res[i] * b;         res[i] = t % 100000000, t /= 100000000;     }     while  (t) res.push_back(t % 100000000), t /= 100000000; } void out(const vector<ll>& res) {     printf ("%lld" , res.back());     for  (int i = res.size()-2; i >= 0; i--) {         printf ("%08lld" , res[i]);     }     printf ("\n" ); } void init  () {     // } int main  () {     freopen("input.txt" , "r" , stdin);     cin >> n;     // get primes     get_primes();     // divide factorial     for  (auto p : primes) pw[p] = get(2*n, p) - 2 * get(n, p);     // divide     int x = n+1;     for  (auto p : primes) if  (p <= x) {         int s = 0;         while  (x % p == 0) s++, x /= p;         pw[p] -= s;     }     // multi     vector<ll> ans;     ans.push_back(1);     for  (auto p : primes) {         for  (int j = 0; j < pw[p]; j++) multi(ans, p);     }     // output     out(ans); }