Template for XCPC
图论
链式前向星
struct EDGE
{
int to, w, next;
} edge[ MAXN] ;
int head[ MAXN] , ptr= 0 ;
void add_edge ( int from, int to, int w)
{
edge[ ++ ptr] . to= to;
edge[ ptr] . w= w;
edge[ ptr] . next= head[ from] ;
head[ from] = ptr;
}
Dijkstra
void dijkstra ( int s)
{
typedef pair< int , int > PII;
set< PII> minHeap;
memset ( d, 0x3f , sizeof ( d) ) ;
minHeap. insert ( make_pair ( 0 , s) ) ;
d[ s] = 0 ;
while ( ! minHeap. empty ( ) )
{
int now= minHeap. begin ( ) -> second;
int dis= minHeap. begin ( ) -> first;
minHeap. erase ( minHeap. begin ( ) ) ;
if ( d[ now] < dis) continue ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to, w= edge[ p] . w;
if ( d[ to] > ( d[ now] + w) )
{
d[ to] = d[ now] + w;
minHeap. insert ( make_pair ( d[ to] , to) ) ;
}
}
}
}
SPFA
bool mark[ N] ;
bool SPFA ( int s, int n)
{
queue< int > que;
int cnt[ N] ;
memset ( cnt, 0 , sizeof ( cnt) ) ;
memset ( d, 0x3f , sizeof ( d) ) ;
que. push ( s) ;
d[ s] = 0 ;
while ( ! que. empty ( ) )
{
int t= que. front ( ) ;
mark[ t] = 0 ;
cnt[ t] ++ ;
if ( cnt[ t] > n)
return 0 ;
que. pop ( ) ;
for ( int i= head[ t] ; i; i= edge[ i] . next)
{
int key= edge[ i] . to, len= edge[ i] . w;
if ( d[ key] > ( d[ t] + len) )
{
d[ key] = d[ t] + len;
if ( mark[ key] == 0 )
que. push ( key) , mark[ key] = 1 ;
}
}
}
return 1 ;
}
Floyd
for ( int i= 0 ; i< m; i++ )
{
int a, b, c;
cin>> a>> b>> c;
mapp[ b] [ a] = mapp[ a] [ b] = c;
}
for ( int k= 2 ; k< n; k++ )
for ( int i= 1 ; i<= n; i++ )
for ( int j= 1 ; j<= n; j++ )
if ( mapp[ i] [ j] > mapp[ i] [ k] + mapp[ k] [ j] )
mapp[ i] [ j] = mapp[ i] [ k] + mapp[ k] [ j] ;
拓扑排序
int in_deg[ MAXN] ;
int ans_seq[ MAXN] , aptr;
int topo ( int n)
{
queue< int > que;
for ( int i= 1 ; i<= n; i++ )
if ( in_deg[ i] == 0 )
que. push ( i) ;
while ( que. size ( ) )
{
int u= que. front ( ) ;
ans_seq[ ++ aptr] = u;
que. pop ( ) ;
for ( int i= head[ u] ; i; i= edge[ i] . next)
{
int to= edge[ i] . to;
in_deg[ to] -- ;
if ( in_deg[ to] == 0 )
que. push ( to) ;
}
}
}
Tarjan
int belong[ MAXN] , scc;
int dfn[ MAXN] , low[ MAXN] ;
int idx;
bool in_stk[ MAXN] ;
stack< int > stk;
void tarjan ( int now)
{
dfn[ now] = low[ now] = ++ idx;
stk. push ( now) ;
in_stk[ now] = 1 ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( ! dfn[ to] )
{
tarjan ( to) ;
low[ now] = min ( low[ now] , low[ to] ) ;
}
else if ( in_stk[ to] )
low[ now] = min ( low[ now] , dfn[ to] ) ;
}
if ( dfn[ now] == low[ now] )
{
int temp;
scc++ ;
do
{
temp= stk. top ( ) ;
belong[ temp] = scc;
in_stk[ temp] = 0 ;
stk. pop ( ) ;
}
while ( temp!= now) ;
}
}
int dfn[ MAXN] , low[ MAXN] , cut[ MAXN] ;
int idx;
void tarjan ( int now, int fa)
{
dfn[ now] = low[ now] = ++ idx;
int child= 0 ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( ! dfn[ to] )
{
tarjan ( to, now) ;
low[ now] = min ( low[ now] , low[ to] ) ;
if ( low[ to] >= dfn[ now] && now!= fa)
cut[ now] = 1 ;
if ( now== fa)
child++ ;
}
low[ now] = min ( low[ now] , dfn[ to] ) ;
}
if ( child>= 2 && now== fa)
cut[ now] = 1 ;
}
2-SAT
vector< int > ans;
bool SAT ( )
{
for ( int i= 2 ; i<= 2 * k+ 1 ; i++ )
if ( ! dfn[ i] )
tarjan ( i) ;
for ( int i= 1 ; i<= k; i++ )
{
if ( belong[ i* 2 ] == belong[ i* 2 + 1 ] )
return false ;
ans. push_back ( belong[ i* 2 ] < belong[ i* 2 + 1 ] ) ;
}
return true ;
}
欧拉路 无向图
vector< int > ans;
int vis[ MAXN] ;
void dfs ( int now)
{
for ( int p= head[ now] ; p; p= edge[ p] . next)
if ( ! vis[ p] )
{
vis[ p] = vis[ p^ 1 ] = 1 ;
dfs ( edge[ p] . to) ;
}
ans. push_back ( now) ;
}
LCA 倍增
int dep[ MAXN] , f[ MAXN] [ 20 ] ;
void dfs ( int now, int fa)
{
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( to== fa) continue ;
dep[ to] = dep[ now] + 1 ;
f[ to] [ 0 ] = now; dfs ( to, now) ;
}
}
void dp ( )
{
for ( int i= 1 ; ( 1 << i) <= n; i++ )
for ( int u= 1 ; u<= n; u++ )
f[ u] [ i] = f[ f[ u] [ i- 1 ] ] [ i- 1 ] ;
}
int lca ( int x, int y)
{
int p, t;
if ( dep[ x] < dep[ y] )
swap ( x, y) ;
for ( p= 0 ; ( 1 << p) <= dep[ x] ; p++ ) ;
for ( t= -- p; t>= 0 ; t-- )
if ( dep[ x] - ( 1 << t) >= dep[ y] )
x= f[ x] [ t] ;
if ( x== y)
return x;
for ( t= p; t>= 0 ; t-- )
if ( f[ x] [ t] != f[ y] [ t] )
x= f[ x] [ t] , y= f[ y] [ t] ;
return f[ x] [ 0 ] ;
}
Kruskal
bool cmp ( EDGE a, EDGE b)
{
return a. w< b. w;
}
int kruskal ( )
{
sort ( edge, edge+ m, cmp) ;
dsu_init ( ) ;
int ans= 0 ;
for ( int i= 0 ; i< m; i++ )
if ( ! is_same ( edge[ i] . u, edge[ i] . v) )
ans+= edge[ i] . w, dsu_merge ( edge[ i] . u, edge[ i] . v) ;
return ans;
}
树的重心
int siz[ MAXN] , w[ MAXN] , minn= INT_MAX, ans= INT_MAX, n;
void dfs ( int now, int fa)
{
siz[ now] = 1 , w[ now] = 0 ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( to== fa) continue ;
dfs ( to, now) ;
w[ now] = max ( w[ now] , siz[ to] ) ;
}
w[ now] = max ( w[ now] , n- siz[ now] ) ;
siz[ fa] += siz[ now] ;
if ( w[ now] < minn)
ans= now, minn= w[ now] ;
}
树链剖分 LCA
int f[ MAXN] , dep[ MAXN] , son[ MAXN] , siz[ MAXN] ;
void dfs1 ( int now, int fa)
{
f[ now] = fa;
siz[ now] = 1 ;
dep[ now] = dep[ fa] + 1 ;
int maxn= 0 ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( to== fa) continue ;
dfs1 ( to, now) ;
siz[ now] += siz[ to] ;
if ( maxn< siz[ to] )
maxn= siz[ to] , son[ now] = to;
}
}
int tim, dfn[ MAXN] , top[ MAXN] , w[ MAXN] , val[ MAXN] ;
void dfs2 ( int now, int t)
{
dfn[ now] = ++ tim;
top[ now] = t;
w[ tim] = val[ now] ;
if ( ! son[ now] ) return ;
dfs2 ( son[ now] , t) ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( to== f[ now] || to== son[ now] ) continue ;
dfs2 ( to, to) ;
}
}
int lca ( int x, int y)
{
while ( top[ x] != top[ y] )
{
if ( dep[ top[ x] ] < dep[ top[ y] ] ) swap ( x, y) ;
x= f[ top[ x] ] ;
}
if ( dep[ x] > dep[ y] ) swap ( x, y) ;
return x;
}
树上启发式合并 CF600E
int f[ MAXN] , dep[ MAXN] , son[ MAXN] , siz[ MAXN] ;
void dfs1 ( int now, int fa)
{
f[ now] = fa;
siz[ now] = 2 ;
dep[ now] = dep[ fa] + 1 ;
int maxn= 0 ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( to== fa) continue ;
dfs1 ( to, now) ;
siz[ now] += siz[ to] ;
if ( maxn< siz[ to] )
maxn= siz[ to] , son[ now] = to;
}
}
int cnt[ MAXN] , val[ MAXN] , maxn, flag, v, sum;
void cal ( int now, int fa, int v)
{
cnt[ val[ now] ] += v;
if ( cnt[ val[ now] ] > maxn)
maxn= cnt[ val[ now] ] , sum= val[ now] ;
else if ( cnt[ val[ now] ] == maxn)
sum+= val[ now] ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( to== fa|| to== flag) continue ;
cal ( to, now, v) ;
}
}
int ans[ MAXN] ;
void dfs2 ( int now, int fa, bool keep)
{
for ( int p= head[ now] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( to== fa|| to== son[ now] ) continue ;
dfs2 ( to, now, 0 ) ;
}
if ( son[ now] )
{
dfs2 ( son[ now] , now, 1 ) ;
flag= son[ now] ;
}
cal ( now, fa, 1 ) ;
flag= 0 ;
ans[ now] = sum;
if ( keep) return ;
cal ( now, fa, - 1 ) ;
sum= maxn= 0 ;
}
Dinic
int lev[ N] , cur[ N] ;
int n, m, s, t;
void bfs ( )
{
memset ( lev, 0 , sizeof ( lev) ) ;
queue< int > que;
lev[ s] = 1 ;
que. push ( s) ;
while ( que. size ( ) )
{
int now= que. front ( ) ;
que. pop ( ) ;
for ( int p= head[ now] ; p; p= edge[ p] . next)
if ( edge[ p] . cap> 0 && lev[ edge[ p] . to] == 0 )
{
lev[ edge[ p] . to] = lev[ now] + 1 , que. push ( edge[ p] . to) ;
if ( edge[ p] . to== t)
return ;
}
}
}
long long dfs ( int from, long long f)
{
if ( from== t)
return f;
long long ret= 0 ;
for ( int p= cur[ from] ; p&& f; p= edge[ p] . next)
{
cur[ from] = p;
if ( lev[ edge[ p] . to] > lev[ from] && edge[ p] . cap> 0 )
{
long long d= dfs ( edge[ p] . to, min ( f, edge[ p] . cap) ) ;
if ( d> 0 )
{
edge[ p] . cap-= d;
edge[ p^ 1 ] . cap+= d;
ret+= d;
f-= d;
}
else
lev[ edge[ p] . to] = 0 ;
}
}
return ret;
}
long long dinic ( )
{
long long flow= 0 ;
for ( ; ; )
{
bfs ( ) ;
if ( lev[ t] == 0 )
return flow;
memcpy ( cur, head, sizeof ( head) ) ;
flow+= dfs ( s, inf) ;
}
}
MCMF
int n, m, s, t, ptr= 1 ;
int pre[ MAXN] ;
int d[ MAXN] ;
bool mark[ MAXN] ;
bool SPFA ( )
{
queue< int > que;
memset ( d, 0x3f , sizeof ( d) ) ;
que. push ( s) ;
d[ s] = 0 ;
while ( ! que. empty ( ) )
{
int now= que. front ( ) ;
mark[ now] = 0 ;
que. pop ( ) ;
for ( int i= head[ now] ; i; i= edge[ i] . next)
{
int to= edge[ i] . to, len= edge[ i] . f;
if ( d[ to] > ( d[ now] + len) && edge[ i] . cap)
{
d[ to] = d[ now] + len;
pre[ to] = i;
if ( mark[ to] == 0 )
que. push ( to) , mark[ to] = 1 ;
}
}
}
if ( d[ t] == inf)
return 0 ;
return 1 ;
}
void MCMF ( int & maxFlow, int & minCost)
{
int sumflow= 0 ;
int minflow, mincost= 0 ;
while ( SPFA ( ) )
{
minflow= inf;
for ( int i= pre[ t] ; i; i= pre[ edge[ i^ 1 ] . to] )
if ( edge[ i] . cap< minflow)
minflow= edge[ i] . cap;
sumflow+= minflow;
for ( int i= pre[ t] ; i; i= pre[ edge[ i^ 1 ] . to] )
{
edge[ i] . cap-= minflow;
edge[ i^ 1 ] . cap+= minflow;
}
mincost+= d[ t] * minflow;
}
maxFlow= sumflow;
minCost= mincost;
}
Hungarian
int partner[ MAXN] ;
bool vis[ MAXN] ;
bool match ( int u)
{
for ( int p= head[ u] ; p; p= edge[ p] . next)
{
int to= edge[ p] . to;
if ( ! vis[ to] )
{
vis[ to] = 1 ;
if ( partner[ to] == 0 || match ( partner[ to] ) )
{
partner[ to] = u;
vis[ to] = 0 ;
return 1 ;
}
}
}
return 0 ;
}
int Hungarian ( )
{
int cnt= 0 ;
for ( int i= 1 ; i<= M; i++ )
if ( match ( i) )
cnt++ ;
return cnt;
}
数据结构
ST表
int log2n[ MAXN] ;
void log_ini ( )
{
log2n[ 1 ] = 0 ;
log2n[ 2 ] = 1 ;
for ( int i= 3 ; i< MAXN; i++ )
log2n[ i] = log2n[ i>> 1 ] + 1 ;
}
int st[ MAXN] [ 20 ] ;
void st_ini ( int n)
{
for ( int j= 1 ; j< log2n[ n] + 1 ; j++ )
for ( int i= 0 ; i+ ( 1 << j) - 1 < n; i++ )
st[ i] [ j] = max ( st[ i] [ j- 1 ] , st[ i+ ( 1 << ( j- 1 ) ) ] [ j- 1 ] ) ;
}
int query ( int l, int r)
{
int p= log2n[ r- l+ 1 ] ;
return max ( st[ l] [ p] , st[ r- ( 1 << p) + 1 ] [ p] ) ;
}
树状数组(单点修改区间查询)
int bit[ MAXN] ;
int lowbit ( int x)
{
return x & - x;
}
void add ( int x, int v)
{
for ( ; x<= MAXN; x+= lowbit ( x) )
bit[ x] += v;
}
int query ( int x)
{
int res= 0 ;
for ( ; x; x-= lowbit ( x) )
res+= bit[ x] ;
return res;
}
线段树(lazy)
struct node
{
int l, r, v, col;
} sgt[ MAXN
void iniSgt ( int p, int l, int r)
{
sgt[ p] . l= l;
sgt[ p] . r= r;
sgt[ p] . v= 0 ;
if ( l== r)
return ;
int mid= ( l+ r) / 2 ;
iniSgt ( p* 2 , l, mid) ;
iniSgt ( p* 2 + 1 , mid+ 1 , r) ;
}
void down ( int p)
{
if ( sgt[ p] . col)
{
int l= sgt[ p] . l, r= sgt[ p] . r;
int mid= ( l+ r) / 2 ;
sgt[ p* 2 ] . v= sgt[ p] . col* ( mid- l+ 1 ) ;
sgt[ p* 2 + 1 ] . v= sgt[ p] . col* ( r- mid) ;
sgt[ p* 2 ] . col= sgt[ p* 2 + 1 ] . col= sgt[ p] . col;
sgt[ p] . col= 0 ;
}
}
void modify ( int p, int L, int R, int v)
{
int l= sgt[ p] . l, r= sgt[ p] . r;
if ( l>= L&& r<= R)
{
sgt[ p] . col= v;
sgt[ p] . v= ( r- l+ 1 ) * v;
return ;
}
down ( p) ;
int mid= ( l+ r) / 2 ;
if ( L<= mid)
modify ( p* 2 , L, R, v) ;
if ( R>= mid+ 1 )
modify ( p* 2 + 1 , L, R, v) ;
sgt[ p] . v= sgt[ p* 2 ] . v+ sgt[ p* 2 + 1 ] . v;
}
int query ( int p, int x, int y)
{
int l= sgt[ p] . l, r= sgt[ p] . r;
if ( x<= l&& y>= r)
return sgt[ p] . v;
down ( p) ;
int mid= ( l+ r) / 2 , res= 0 ;
if ( x<= mid)
res+= query ( p* 2 , x, y) ;
if ( y> mid)
res+= query ( p* 2 + 1 , x, y) ;
return res;
}
DSU
int dsu[ MAXN] ;
void init ( )
{
for ( int i= 0 ; i< MAXN; i++ )
dsu[ i] = i;
}
void fnd ( int x)
{
if ( dsu[ x] == x) return x;
return dsu[ x] = fnd ( dsu[ x] ) ;
}
void merg ( int x, int y)
{
dsu[ fnd ( x) ] = fnd ( y) ;
}
主席树
struct node
{
int ls, rs, v;
} st[ MAXN] ; int ptr;
void iniSt ( int & p, int l, int r)
{
p= ++ ptr;
if ( l== r) return ;
int mid= ( l+ r) / 2 ;
iniSt ( st[ p] . ls, l, mid) ;
iniSt ( st[ p] . rs, mid+ 1 , r) ;
}
int modify ( int p, int l, int r, int x, int v)
{
int np= ++ ptr;
st[ np] = st[ p] ;
if ( l== r)
{
st[ np] . v+= v;
return np;
}
int mid= ( l+ r) / 2 ;
if ( x<= mid)
st[ np] . ls= modify ( st[ np] . ls, l, mid, x, v) ;
else
st[ np] . rs= modify ( st[ np] . rs, mid+ 1 , r, x, v) ;
st[ np] . v= st[ st[ np] . ls] . v+ st[ st[ np] . rs] . v;
return np;
}
int rt[ MAXN] ;
int ask ( int p1, int p2, int l, int r, int c)
{
if ( l== r) return l;
int mid= ( l+ r) / 2 ;
if ( st[ st[ p2] . ls] . v- st[ st[ p1] . ls] . v>= c)
return ask ( st[ p1] . ls, st[ p2] . ls, l, mid, c) ;
else
return ask ( st[ p1] . rs, st[ p2] . rs, mid+ 1 , r, c- ( st[ st[ p2] . ls] . vst[ st[ p1] . ls] . v) ) ;
}
字典树
int * ch[ MAXN] , cnt[ MAXN] , tot;
void update ( string s)
{
int ptr= 0 ;
for ( int i= 0 ; i< s. size ( ) ; i++ )
{
if ( ch[ ptr] == NULL )
{
ch[ ptr] = new int [ MAXC] ;
memset ( ch[ ptr] , 0 , sizeof ( int ) * MAXC) ;
}
int * nextNode= & ch[ ptr] [ s[ i] - 'a' ] ;
if ( * nextNode== 0 )
* nextNode= ++ tot;
ptr= * nextNode;
}
cnt[ ptr] ++ ;
}
int query ( string s)
{
int ptr= 0 ;
for ( int i= 0 ; i< s. size ( ) ; i++ )
{
if ( ch[ ptr] == NULL || ch[ ptr] [ s[ i] - 'a' ] == 0 )
return 0 ;
ptr= ch[ ptr] [ s[ i] - 'a' ] ;
}
return cnt[ ptr] ;
}
字符串
KMP
int next[ N] ;
void getNext ( string s)
{
int j= 0 , k= - 1 ;
next[ j] = k;
while ( j< s. size ( ) )
if ( k== - 1 || s[ j] == s[ k] )
next[ ++ j] = ++ k;
else
k= next[ k] ;
}
void kmp ( string s, string str)
{
int j= 0 , k= 0 , res= 0 ;
for ( ; j!= str. size ( ) ; j++ )
{
while ( k!= - 1 && s[ k] != str[ j] )
k= next[ k] ;
k++ ;
if ( k== s. size ( ) )
cout<< j- s. size ( ) + 1 << ' ' ;
}
}
EX-KMP
int next[ N] ;
int extend[ N] ;
void getNext ( string s)
{
int m= s. size ( ) ;
int a = 0 , p = 0 ;
next[ 0 ] = m;
for ( int i= 1 ; i< m; i++ )
{
if ( i+ next[ i- a] >= p)
{
if ( i>= p)
p= i;
while ( p< m&& s[ p] == s[ p- i] )
p++ ;
next[ i] = p- i;
a= i;
}
else
next[ i] = next[ i- a] ;
}
}
void getExtend ( string str, string s)
{
int n= str. size ( ) , m= s. size ( ) ;
int a = 0 , p = 0 ;
getNext ( s) ;
for ( int i= 0 ; i< n; i++ )
{
if ( i+ next[ i- a] >= p)
{
if ( i>= p)
p= i;
while ( p< n&& p- i< m&& str[ p] == s[ p- i] )
p++ ;
extend[ i] = p- i;
a= i;
}
else
extend[ i] = next[ i- a] ;
}
}
AC自动机
int ch[ MAXN] [ MAXC] , cnt[ MAXN] , tot, mark[ MAXN] , app[ MAXN] ;
int next[ MAXN] , ptr, head[ MAXN] ;
struct edge
{
int to, next;
} edge[ MAXN] ;
void update ( string s, int m)
{
int ptr= 0 ;
for ( int i= 0 ; i< s. size ( ) ; i++ )
{
int * nextNode= & ch[ ptr] [ s[ i] - 'a' ] ;
if ( * nextNode== 0 )
* nextNode= ++ tot;
ptr= * nextNode;
}
cnt[ ptr] ++ ;
mark[ m] = ptr;
}
void add_edge ( int u, int v)
{
edge[ ptr] . to= v;
edge[ ptr] . next= head[ u] ;
head[ u] = ptr++ ;
}
int getNext ( )
{
queue< int > que;
for ( int i= 0 ; i< MAXC; i++ )
{
if ( ch[ 0 ] [ i] > 0 )
{
next[ ch[ 0 ] [ i] ] = 0 ;
que. push ( ch[ 0 ] [ i] ) ;
}
}
while ( que. size ( ) )
{
int now= que. front ( ) ;
que. pop ( ) ;
for ( int i= 0 ; i< MAXC; i++ )
if ( ch[ now] [ i] > 0 )
{
next[ ch[ now] [ i] ] = ch[ next[ now] ] [ i] ;
que. push ( ch[ now] [ i] ) ;
}
else
ch[ now] [ i] = ch[ next[ now] ] [ i] ;
}
for ( int i= 1 ; i<= tot; i++ )
add_edge ( next[ i] , i) ;
}
int query ( string s)
{
int now= 0 , ans= 0 ;
for ( int i= 0 ; i< s. size ( ) ; i++ )
{
now= ch[ now] [ s[ i] - 'a' ] ;
app[ now] ++ ;
}
return ans;
}
void dfs ( int now)
{
for ( int i= head[ now] ; i!= - 1 ; i= edge[ i] . next)
{
dfs ( edge[ i] . to) ;
app[ now] += app[ edge[ i] . to] ;
}
}
数学
快速幂
int qpow ( int a, int n) {
int ans = 1 ;
while ( n) {
if ( n& 1 )
ans *= a;
a *= a;
n >>= 1 ;
}
return ans;
}
欧拉定理、费马小定理
当a与n互质
a^ φ( n) % n == 1
a^ ( p- 1 ) % p == 1
除法取模
( b/ a) % m == b* a^ ( m- 2 ) % m
线性筛
int vis[ N] , prim[ N] ;
int pn = 0 ;
void table ( ) {
for ( int i = 2 ; i < N; i++ ) {
if ( ! vis[ i] ) prim[ pn++ ] = i;
for ( int j = 0 ; j < pn && 1LL * i* prim[ j] < N; j++ ) {
vis[ i* prim[ j] ] = 1 ;
if ( i % prim[ j] == 0 ) break ;
}
}
}
欧拉函数
int euler ( int n)
{
if ( n== 1 ) return 1 ;
int res= n;
for ( int i= 0 , p= prim[ i] ; p* p<= n; i++ , p= prim[ i] )
if ( n% p== 0 )
{
res= res/ p* ( p- 1 ) ;
while ( n% p== 0 ) n/= p;
}
if ( n> 1 ) res= res/ n* ( n- 1 ) ;
return res;
}
筛法求欧拉函数
int vis[ N] , prim[ N] ;
int phi[ N] ;
int pn = 0 ;
void table ( )
{
phi[ 1 ] = 1 ;
for ( int i = 2 ; i < N; i++ )
{
if ( ! vis[ i] )
{
prim[ pn++ ] = i;
phi[ i] = i- 1 ;
}
for ( int j = 0 ; j < pn && 1LL * i* prim[ j] < N; j++ )
{
vis[ i* prim[ j] ] = 1 ;
if ( i % prim[ j] == 0 )
{
phi[ i* prim[ j] ] = phi[ i] * prim[ j] ;
break ;
}
phi[ i* prim[ j] ] = phi[ i] * ( prim[ j] - 1 ) ;
}
}
}
矩阵
struct mat
{
int m[ N+ 1 ] [ N+ 1 ] ;
mat ( ) { memset ( m, 0 , sizeof ( m) ) ; }
mat ( int n) { mat ( ) ; for ( int i= 1 ; i<= N; i++ ) m[ i] [ i] = n; }
mat operator * ( const mat& b)
{
mat ret;
for ( int i= 1 ; i<= N; i++ )
for ( int k= 1 ; k<= N; k++ )
for ( int j= 1 ; j<= N; j++ )
ret. m[ i] [ j] += m[ i] [ k] * b. m[ k] [ j] , ret. m[ i] [ j] %= MOD;
return ret;
}
mat operator + ( const mat& b)
{
mat ret;
for ( int i= 1 ; i<= N; i++ )
for ( int j= 1 ; j<= N; j++ )
ret. m[ i] [ j] = ( m[ i] [ j] + b. m[ i] [ j] ) % MOD;
return ret;
}
} ;
扩展欧几里得
int exgcd ( int a, int b, int & x, int & y)
{
if ( ! b)
{
x= 1 , y= 0 ;
return a;
}
int d= exgcd ( b, a% b, y, x) ;
y-= a/ b* x;
return d;
}
龟速乘
int lmul ( int x, int y, const int & mod)
{
int ans= 0 ;
while ( y)
{
if ( y& 1 ) ans= ( ans+ x) % mod;
x= ( x+ x) % mod;
y>>= 1 ;
}
return ans;
}
扩展中国剩余定理
int exCRT ( int n, int * A, int * B)
{
int x, y, ans= A[ 1 ] , M= B[ 1 ] , bg;
for ( int i= 2 ; i<= n; i++ )
{
int a= M, b= B[ i] , c= ( A[ i] - ans% b+ b) % b;
int gcd= exgcd ( M, b, x, y) ;
bg= b/ gcd;
if ( c% gcd!= 0 ) return - 1 ;
x= lmul ( x, c/ gcd, bg) ;
ans+= x* M;
M*= bg;
ans= ( ans% M+ M) % M;
}
return ans;
}
高斯消元
int gauss ( int n)
{
const double eps= 1e-8 ;
int c, r;
for ( c = 0 , r = 0 ; c < n; c ++ )
{
int t = r;
for ( int i = r; i < n; i ++ )
if ( fabs ( a[ i] [ c] ) > fabs ( a[ t] [ c] ) )
t = i;
if ( fabs ( a[ t] [ c] ) < eps) continue ;
for ( int i = c; i <= n; i ++ ) swap ( a[ t] [ i] , a[ r] [ i] ) ;
for ( int i = n; i >= c; i -- ) a[ r] [ i] /= a[ r] [ c] ;
for ( int i = r + 1 ; i < n; i ++ )
if ( fabs ( a[ i] [ c] ) > eps)
for ( int j = n; j >= c; j -- )
a[ i] [ j] -= a[ r] [ j] * a[ i] [ c] ;
r ++ ;
}
if ( r < n)
{
for ( int i = r; i < n; i ++ )
if ( fabs ( a[ i] [ n] ) > eps)
return - 1 ;
return n- r;
}
for ( int i = n - 1 ; i >= 0 ; i -- )
for ( int j = i + 1 ; j < n; j ++ )
a[ i] [ n] -= a[ i] [ j] * a[ j] [ n] ;
return 0 ;
}
卢卡斯定理
int C ( int a, int b)
{
int res = 1 ;
for ( int i = 1 , j = a; i <= b; i ++ , j -- )
{
res = ( LL) res * j % p;
res = ( LL) res * qpow ( i, p - 2 ) % p;
}
return res;
}
int lucas ( int a, int b)
{
if ( a < p && b < p) return C ( a, b) ;
return C ( a % p, b % p) * lucas ( a / p, b / p) % p;
}
快速傅里叶变换
const int N= 1050000 ;
const double PI= acos ( - 1.0 ) ;
struct CP {
CP ( double xx= 0 , double yy= 0 ) { x= xx, y= yy; }
double x= 0 , y= 0 ;
CP operator + ( CP const & B) const
{ return CP ( x+ B. x, y+ B. y) ; }
CP operator - ( CP const & B) const
{ return CP ( x- B. x, y- B. y) ; }
CP operator * ( CP const & B) const
{ return CP ( x* B. x- y* B. y, x* B. y+ y* B. x) ; }
} f[ N<< 1 ] , p[ N<< 1 ] ;
int tr[ N<< 1 ] ;
void fft ( int n, CP * f, bool flag) {
for ( int i= 0 ; i< n; i++ ) {
if ( i< tr[ i] ) swap ( f[ i] , f[ tr[ i] ] ) ;
}
for ( int p= 2 ; p<= n; p<<= 1 ) {
int len= p>> 1 ;
CP tG ( cos ( 2 * PI/ p) , sin ( 2 * PI/ p) ) ;
if ( ! flag) tG. y*= - 1 ;
for ( int k= 0 ; k< n; k+= p) {
CP buf ( 1 , 0 ) ;
for ( int l= k; l< k+ len; l++ ) {
CP tt= buf* f[ len+ l] ;
f[ len+ l] = f[ l] - tt;
f[ l] = f[ l] + tt;
buf= buf* tG;
}
}
}
}
int FFT ( int n, int m)
{
for ( m+= n, n= 1 ; n<= m; ) n<<= 1 ;
for ( int i= 0 ; i<= n- 1 ; i++ ) {
tr[ i] = ( tr[ i>> 1 ] >> 1 ) | ( ( i& 1 ) ? n>> 1 : 0 ) ;
}
fft ( n, f, 1 ) ; fft ( n, p, 1 ) ;
for ( int i= 0 ; i<= n- 1 ; i++ ) f[ i] = f[ i] * p[ i] ;
fft ( n, f, 0 ) ;
for ( int i= 0 ; i<= m; i++ ) f[ i] . x = ( int ) ( f[ i] . x/ n+ 0.49 ) ;
return m;
}
杂项
二进制枚举子集
for ( int i = s; i; i = ( i - 1 ) & s)
快读快写
inline void read ( __int128 & x)
{
int f = 1 ;
x = 0 ;
char ch = getchar ( ) ;
while ( ch < '0' || ch > '9' )
{
if ( ch == '-' )
f *= - 1 ;
ch = getchar ( ) ;
}
while ( ch >= '0' && ch <= '9' )
{
x = x* 10 + ch- '0' ;
ch = getchar ( ) ;
}
x *= f;
}
inline void print ( __int128 x)
{
if ( x < 0 )
{
putchar ( '-' ) ;
x = - x;
}
if ( x > 9 )
print ( x/ 10 ) ;
putchar ( x% 10 + '0' ) ;
}
数位DP
int a, b;
int upperBound[ MAXN] ;
int dp[ MAXN] [ MAXN] ;
int split ( int x)
{
int ptr= 0 ;
while ( x)
upperBound[ ptr++ ] = x% 10 , x/= 10 ;
return ptr;
}
int split ( string x)
{
for ( int i= 0 ; i< x. size ( ) ; i++ )
upperBound[ i] = x[ x. size ( ) - i- 1 ] ;
return x. size ( ) ;
}
int dfs ( int pos, int pre_num, bool lead, bool flag)
{
if ( pos== - 1 )
return 1 ;
if ( ! flag&& dp[ pos] [ pre_num] != - 1 )
return dp[ pos] [ pre_num] ;
int up= flag? upperBound[ pos] : 9 , ret= 0 ;
for ( int i= 0 ; i<= up; i++ )
if ( abs ( i- pre_num) >= 2 || lead&& i== 0 )
ret+= dfs ( pos- 1 , i, lead&& i== 0 , flag&& i== up) ;
if ( ! flag&& ! lead)
dp[ pos] [ pre_num] = ret;
return ret;
}
int solve ( int x)
{
if ( x< 0 ) return 0 ;
memset ( dp, - 1 , sizeof ( dp) ) ;
int len= split ( x) ;
return dfs ( len- 1 , 0 , 1 , 1 ) ;
}