UPD during 2018 4 17 to 2019 9 24 新增很多内容
UPD at 2018 4 16 [ 10:42 ] 降级FWT,新增「dp套dp」
UPD at 2018 3 24 [ 15:43 ] 新增部分内容,删除了「拟阵」
按照省选+ 难度 分级
数论
- gcd,EXgcd
- Lucas定理,扩展Lucas
- 中国剩余定理,扩展中国剩余定理
- 杨辉三角递推式(以及相关等式)
- 卡特兰数h(n) = C(2n,n-1)/n
- 错排D(n)=(n-1)(D(n-1)+D(n-2))
- 原根
- BSGS
- 线性基
- 高斯消元
- 容斥原理(莫比乌斯容斥系数,二进制容斥,Min_Max容斥)
- 快速幂,矩阵快速幂
- 线性筛
- 杜教筛, ∗ * ∗ 洲阁筛, ∗ * ∗ Min_25筛
- FWT 位运算卷积
- FFT&NTT 多项式卷积
- ∗ * ∗ 子集卷积
- 群论基础知识,置换群(Burnside引理 + polya计数)
- Miller-Rabin大质数检验
- Pollard rho大数分解质因数
- ∗ * ∗ 单纯型
- ∗ * ∗ 线性递推
- ∗ * ∗ 差分表
- ∗ * ∗ 多项式那一大堆
- ∗ * ∗ 杨表(Young diagram)
信息学奥林匹克数学竞赛,真不是吹的
建议多看看各种数学书,多get一点技巧(离散数学,具体数学等等)
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
const int mmod = 1e9 + 7 , N = 5000 ;
int C[5005][5005] , fac[100005] , inv[100005] , D[100005] ;
int p[1000005] , phi[1000005] , miu[1000005] , tao[1000005] , d[1000005] , topp ;
bool isnotp[1000005] ;
void get_P(){
phi[1] = 0 ;
miu[1] = 1 ;
for( int i = 2 ; i <= 1000000 ; i ++ ){
if( !isnotp[i] ){
p[++topp] = i ;
phi[i] = i - 1 ;
miu[i] = -1 ;
tao[i] = 2 , d[i] = 1 ;
}
for( int j = 1 ; j <= topp && i * p[j] <= 1000000 ; j ++ ){
if( i % p[j] == 0 ){
//i中包含 p[j] ,现在又多了一个 p[j]
//也就是原来 i 和它互质的数,记为 k ,现在变成了 1*k,2*k,3*k...p[j]*k
//而这些 1*k,2*k,3*k...p[j]*k 一定和 i*p[j]互质
//http://blog.csdn.net/Lytning/article/details/24432651
phi[ i*p[j] ] = phi[i] * p[j] ;
//miu根据定义可得
miu[ i*p[j] ] = 0 ;
//num = p1^t1 + p2^t2 + ... + pn^tn ;
//tao[num] = ( t1 + 1 ) * ( t2 + 1 ) * ... * ( tn + 1 ) ;
//tao[ num*p[j] ] = tao[num] / ( d[i] + 1 ) * ( d[i] + 1 + 1 ) ;
tao[ i*p[j] ] = tao[i] / ( d[i] + 1 ) * ( d[i] + 2 ) ;
d[ i*p[j] ] = d[i] + 1 ;
break ;
}
phi[ i*p[j] ] = phi[i] * phi[ p[j] ] ;
miu[ i*p[j] ] = miu[i] * -1 ;
tao[ i*p[j] ] = tao[i] * 2 ;
d[ i*p[j] ] = 1 ;
}
}
}
//杨辉三角:C[i][j] = C[i-1][j] + C[i-1][j-1]
void preWork_C() {
C[0][0] = 1 ;
for( int i = 1 ; i <= 5000 ; i ++ ) {
C[i][0] = 1 ;
for( int j = 1 ; j <= i ; j ++ )
C[i][j] = ( C[i-1][j] + C[i-1][j-1] ) %mmod ;
}
}
//阶乘:fac[i] = fac[i-1] * i
void preWork_fac() {
fac[0] = 1 ;
for( int i = 1 ; i <= 100000 ; i ++ )
fac[i] = 1LL * fac[i-1] * i %mmod ;
}
//错排公式:D[i] = ( i - 1 )*( D[i-1] + D[i-2] )
void preWork_cuopai() {
D[1] = 0 ; D[2] = 1 ;
for( int i = 3 ; i <= 100000 ; i ++ )
D[i] = 1LL * ( i - 1 ) * ( D[i-1] + D[i-2] ) %mmod ;
}
//
int gcd( int a , int b ) {
if( !b ) return a ;
return gcd( b , a%b ) ;
}
//
long long exgcd( long long a , long long b , long long &x , long long &y ) {
if( !b ) {
x = 1 , y = 0 ;
return a ;
} else {
long long xx , yy , d = exgcd( b , a%b , xx , yy ) ;
x = yy , y = xx - a / b * yy ;
return d ;
}
}
//只有x和p互质时,才存在逆元
int get_inv( int x , int p ) {
long long inv , tmp ;
exgcd( x , p , inv , tmp ) ;
return ( inv %mmod + mmod ) %mmod ;
}
//同上,阶乘的逆元,用于算组合数
void preWork_facinv() {
inv[100000] = get_inv( fac[100000] , mmod ) ;
for( int i = 99999 ; i >= 0 ; i -- )
inv[i] = 1LL * inv[i+1] * ( i + 1 ) %mmod ;
}
//组合数: n! / m! / (n-m)! = n! * inv[m!] * inv[(n-m)!]
int comb( int n , int m ){
return 1LL * fac[n] * inv[m] %mmod * inv[n-m]%mmod ;
}
//卡特兰公式: C(2n,n-1)/n
int catalan( int x ){
return 1LL * comb( 2 * x , x - 1 ) * get_inv( x , mmod ) %mmod ;
}
//要求模数为质数
long long Lucas( long long n , long long m ) {
if( n < m ) return 0 ;
if( n >= mmod )
return Lucas( n/mmod , m/mmod ) * comb( n%mmod , m%mmod ) ;
else return C[n][m] ;
}
//要求mi两两互质
//http://blog.csdn.net/clove_unique/article/details/54571216
void CRT(){
int cnt , m[100] , c[100] ;
long long M = 1 , ans = 0 ;
scanf( "%d" , &cnt ) ;
for( int i = 1 ; i <= cnt ; i ++ ){
scanf( "%d%d" , &m[i] , &c[i] ) ;
M *= m[i] ;
}
for( int i = 1 ; i <= cnt ; i ++ ){
long long Mi = M / m[i] ;
ans = ( ans + c[i] * Mi %mmod * get_inv( Mi , m[i] ) ) %mmod ;
}
}
int main( int argc , char *argv[] ) {
preWork_C() ;
preWork_fac() ;
preWork_facinv() ;
get_P() ;
return 0 ;
}
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
/*********************
* BSGS
* POJ 2417
* to solve x that fit
* B^x == N ( mod P )
********************/
int mmod , B , N ;
struct hashTable{
int head[7333] , num[100005] , pw[100005] , pre[100005] , tp ;
void init(){
memset( head , 0 , sizeof( head ) ) ;
tp = 0 ;
}
void Insert( int x , int k ){
int id = x%7333 ;
for( int i = head[id] ; i ; i = pre[i] )
if( num[i] == x ) return ;
pre[++tp] = head[id] ;
num[ head[id] = tp ] = x ;
pw[tp] = k ;
}
int Query( int x ){
int id = x%7333 ;
for( int i = head[id] ; i ; i = pre[i] )
if( num[i] == x ) return pw[i] ;
return 0 ;
}
}HT ;
long long s_pow( long long x , long long b ){
long long rt = 1 ;
while( b ){
if( b&1 ) rt = rt * x %mmod ;
x = x * x %mmod ; b >>= 1 ;
}
return rt ;
}
int BSGS(){
if( N == 1 && B != 0 ) return 0 ;
int sqr = ceil( sqrt( mmod ) ) ;
long long now = N , Bsqr = 1 ;
for( int i = 1 ; i <= sqr ; i ++ ){
now = now * B %mmod ; Bsqr = Bsqr * B %mmod ;
if( Bsqr == N ) return i ;
HT.Insert( now , i ) ;
}
now = Bsqr ;
for( int i = 1 ; i <= sqr ; i ++ ){
int tmp = HT.Query( now ) ;
if( tmp ) return i * sqr - tmp ;
now = now * Bsqr %mmod ;
}
return -1 ;
}
int main(){
while( scanf( "%d%d%d" , &mmod , &B , &N ) != EOF ){
HT.init() ;
int tmp = BSGS() ;
if( tmp == -1 ) puts( "no solution" ) ;
else printf( "%d\n" , tmp ) ;
}
}
图论
- 桥,割点
- 强连通分量(tarjan, ∗ * ∗ Kosaraju),点双连通分量
- ∗ * ∗ 圆方树
- dfs序,树链剖分,括号序,欧拉序
- 倍增LCA,(另tarjan O(n)LCA)
- 欧拉回路(Fleury算法),哈密顿回路
- 最小生成树(Kruskal, ∗ * ∗ Prim, ∗ * ∗ Boruvka), ∗ * ∗ 曼哈顿距离(平面图)最小生成树, ∗ * ∗ 欧几里德距离最小生成树(算几)
- Kruskal重构树
- 最短路(dijkstra,floyd,SPFA),最短路径树
- ∗ * ∗ K短路(堆维护非树边,不是A*)
- 差分约束系统
- ∗ * ∗ 单纯型
- 二分图(染色)
- 匈牙利算法(add:最小覆盖,最长反链,最小路径覆盖…), ∗ * ∗ KM算法
- ∗ * ∗ 带花树
- 网络流(add:最小割,最大权闭合子图,01分数规划),费用流,上下界网络流
- 平面图转对偶图
- 树的重心/直径
- 拓扑排序
- ∗ * ∗ 朱流算法(tarjan有一个nlog的实现)
- 2-SAT
- ∗ * ∗ prufer编码
- Matrix-Tree定理
- ∗ * ∗ 弦图(完美消除序列,MCS算法,Clique tree)
数据结构
- 栈,队列(双端队列),链表(二维链表)
- 并查集
- ST表(RMQ, ∗ * ∗ O(n)RMQ )
- 堆(手写堆,优先队列)
- 平衡树(set,map,Treap ,Splay,替罪羊树)
- 树状数组
- 线段树(永久化标记, ∗ * ∗ ZKW线段树, ∗ * ∗ 李超线段树, ∗ * ∗ Segment-tree-Beats,线段树合并)
- 可并堆(左偏树,斜堆)
- 主席树
- 分块,树分块(莫队,树上莫对)
- 点分治,动态点分治
- LCT, ∗ * ∗ ETT
- ∗ * ∗ 跳表
- ∗ * ∗ 猫树
- 树套树( ∗ * ∗ 套树^n,n≥3)
- ∗ * ∗ 可持久化数据结构
博弈论
- NIM游戏
- SG函数, ∗ * ∗ anti-SG
- ∗ * ∗ alpha-beta 对抗搜索
- 二分图博弈
关于NIM和SG,参见:zyf2000-关于 Nim游戏与SG函数 的一点研究
搜索
- BFS
- DFS
- ∗ * ∗ 分支定界
- 换顺序搜(倒着搜,斜着搜,随便乱搜)
- A*
- IDDFS
- ∗ * ∗ alpha-beta 对抗搜索
- ∗ * ∗ Bron–Kerbosch算法
- ∗ * ∗ Dancing-Link
字符串
- KMP
- Hash
- manacher
- trie树
- AC自动机(trie图,fail树)
- 后缀数组
- 后缀自动机
- 回文自动机
- 最小表示法
- ∗ * ∗ Z-Algorithm
- ∗ * ∗ 后缀平衡树
- ∗ * ∗ Huffman编码
DP
- 背包DP
- 区间DP
- 状压DP
- 数位DP
- 树形DP
- 期望DP
- 瞎JBDP
- ∗ * ∗ 插头DP
- ∗ * ∗ DP套DP(用一个DP来当另一个DP的状态)
- 矩阵维护的动态dp
- 单调队列优化
- 斜率优化(斜率单调,二分斜率)
- ∗ * ∗ 四边形优化
- dp凸优化
- 数据结构优化
- ∗ * ∗ 针对石子合并的GarsiaWachs算法
计算几何
- 向量基础运算(加减乘除,点乘叉乘,向量旋转等)
- 直线求交点
- 求多变形面积
- 求多边形重心
- 判断点在凸多边形内部
- 凸包
- 半平面交
- 旋转卡壳
- ∗ * ∗ 最小圆覆盖
- 自适应simpson积分
其他
- ∗ * ∗ 主定理(分析复杂度用的)
- 二分答案
- 补集转化
- 倍增/二进制拆分
- 差分/前缀和
- 数据分治(根号分治, ∗ * ∗阈值法)
- Hash
- CDQ,整体二分,线段树分治
- 贪心
- 扫描线
- 莫队
- 离散化
- 启发式合并
- DSU on tree
- 树链的并
- ∗ * ∗ 模拟退火, ∗ * ∗ 爬山算法
一些比较散的知识点:
- ∗ * ∗ 龙凡《一类猜数问题的研究》
- ∗ * ∗ DFA,NFA,DFA最小化