syqwq code template

syqwq code template

TOC

ff. TODO

  • 杜教筛
  • 整除分块
  • 广义莫比乌斯反演
  • 异或方程组板子 bitset

0. general

cpp 复制代码
#include <bits/stdc++.h>
#define rep(i, a, b) for (ll i = a; i <= b; i++)
#define per(i, a, b) for (ll i = a; i >= b; i--)
#define pb push_back
#define vc vector
#define fi first
#define se second
#define all(x, n) (x) + 1, (x) + 1 + n
#define NL "\n"
#define NN " "
using namespace std;
typedef long long ll;
typedef vc<ll> vi;
typedef pair<ll, ll> PII;
typedef vc<PII> vpii;
template<class T,class S>
bool chmax(T& x,S y){ return x<y?x=y,1:0; }
template<class T,class S>
bool chmin(T& x,S y){ return x>y?x=y,1:0; }
// #define CF
// #define int long long
//  ================================================

void solve() {
}
//  ================================================
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cout.setf(ios::fixed), cout.precision(5);
    int T = 1;
#ifdef CF
    cin >> T;
#endif // CF
    while (T--) solve();
    return 0;
}

1. Graph theory

1.0 basic build graph

cpp 复制代码
vpii e[N];
void add(int a,int b,int c){e[a].pb({b,c});}
// ==============================================
int idx=0,h[N],ne[M],to[M],w[M];
void add(int a,int b,int c){
    w[++idx]=c,to[idx]=b,ne[idx]=h[a],ha[a]=idx;
}

1.1 tarjan SCC

有向图中的scc要求当前点能够到达所有点,并且其他点能到当前点,于是利用这个思想,在dfs遍历的时候按照时间戳压栈,那么在上面的点就是他能到的点(如果维护一定性质的话)直到遍历完,如果发现当前点就是这个连通块的最高的点(也就是dfn最小的点),那就把这个scc中的点全部出栈。 scc缩点之后,得到的是拓扑图。

cpp 复制代码
vi e[N];
int dn=0,dfn[N],low[N],stc[N],top=0;
int col[N],cn=0,sz[N];

void scc(int id){
    low[id]=dfn[id]=++dn;
    stc[++top]=id,ins[id]=1;
    for(int it:e[id]){
      if(!dfn[it]){
          scc(it),chmin(low[id],low[it]);
      }else if(ins[it]) chmin(low[id],dfn[it]);
    }
    if(low[id]==dfn[id]){
        cn++;int x;
        do{
          col[x=stc[top--]]=cn,ins[x]=0,sz[cn]++;
        }while(x!=id);
    }
}

1.2 tarjan eDCC

解决方法是记录边的编号。对于 vector,在 push_back 时将当前边的编号一并压入。对于链式前向星,使用成对变换技巧:初始化 cnt = 1,每条边及其反边在链式前向星中存储的编号分别为 2k2k+1 ,将当前边编号异或 1 即得反边编号。时间复杂度 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n + m ) O(n+m) </math>O(n+m) 边双缩点之后,得到的是连通分量作为节点的树。

cpp 复制代码
int dfn[N],low[N],dn=0;
int stc[N],top=0;
int cn=0,col[M];

void form(int id){
    cn++;
    for(int x=0;x!=id;) col[x=stc[top--]]=cn;
}
void dcc(int id,int eid){
    stc[++top]=id,dfn[id]=low[id]=++dn;
    for(auto _:e[id]){
        if(_.se==eid) continue;
        int it=_.fi;
        if(!dfn[it]){
            dcc(it,_.se);
            chmin(low[id],low[it]);
            if(low[it]>low[id]) form(it);
        }else chmin(low[id],dfn[it]);
    }
    if(!eid) form(id);
}

1.3 tarjan vDCC

还不会 呜呜呜

1.4 LCA

倍增法,先预处理深度和倍增祖先,然后先跳到一起,再一起跳。时间复杂度 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n) 预处理, <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( log ⁡ n ) O(\log n) </math>O(logn) 查询

cpp 复制代码
int dep[N],anc[N][20];
namespace ZX{   // zu xian
  	void bfs(int root){
    	  queue<int> q;
    	  dep[root]=1,q.push(root);
    	  while(q.size()){
	      	  int id=q.front();q.pop();
	      	  for(auto it:e[id]){
	        	    if(dep[it]) continue;
	        	    dep[it]=dep[id]+1;
	        	    anc[it][0]=id;
	        	    rep(i,1,19) anc[it][i]=anc[anc[it][i-1]][i-1];
	        	    q.push(it);
	      	  }
    	  }
    }
    int lca(int x,int y){
        if(dep[x]<dep[y]) swap(x,y);
		    per(i,19,0) if(dep[anc[x][i]]>=dep[y]) x=anc[x][i];
		    if(x==y) return x;
		    per(i,19,0)
		        if(anc[x][i]!=anc[y][i]) x=anc[x][i],y=anc[y][i];
		    return anc[x][0];
	  }
}

2. Math

2.1 Number theory

2.1.1 Eular sieve

线性筛,时间复杂度 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n)

cpp 复制代码
vi primes;
bool st[N];
void ss(int maxn){
    for(int i=2;i<=maxn;i++){
        if(!st[i]) primes.pb(i);
        for(int j:primes){
          if(j>maxn/i) break;
          st[i*j]=1;
          if(i%j==0) break;
      }
    }
}
2.1.2 Eratothenes sieve

埃式筛,时间复杂度 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n log ⁡ log ⁡ n ) O(n\log \log n) </math>O(nloglogn),修改内层循环可以做区间筛

cpp 复制代码
vi primes;
bitset<N> st;
void ass(int maxn){
    for(int i=2;i<=maxn;i++){
        if(st[i]) continue;
        primes.pb(i);
        for(int j=i*2;j<=maxn;j+=i) st[j]=1;
    }
}
2.1.3 gcd

<math xmlns="http://www.w3.org/1998/Math/MathML"> ( a , b ) = ( a , b − a ) = ( b , a − b ) (a,b)=(a,b-a)=(b,a-b) </math>(a,b)=(a,b−a)=(b,a−b),时间复杂度 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( log ⁡ min ⁡ { a , b } ) ) O(\log \min\{ a,b \})) </math>O(logmin{a,b}))

cpp 复制代码
ll gcd(ll x,ll y){ return y ? x : gcd(y, x%y); }

也可以,cpp内置 __gcd(x,y)

2.2.4 exgcd

方程 <math xmlns="http://www.w3.org/1998/Math/MathML"> a x + b y = gcd ⁡ ( a , b ) ax+by=\operatorname{gcd}(a,b) </math>ax+by=gcd(a,b) 的一组特解,通解是 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( x , y ) = ( x 0 + k ⋅ b ( a , b ) , y 0 − k ⋅ a ( a , b ) ) , k ∈ Z (x,y)=(x_0+k\cdot \frac{b}{(a,b)},y_0-k\cdot \frac{a}{(a,b)}),k\in \mathbb{Z} </math>(x,y)=(x0+k⋅(a,b)b,y0−k⋅(a,b)a),k∈Z

cpp 复制代码
void exgcd(int a, int b, int &x, int &y) {
    if(!b) return x = 1, y = 0, void();
    exgcd(b, a % b, y, x), y -= a / b * x;
}
2.2.5 lowbit
cpp 复制代码
ll lowbit(ll x){ return x&(-x); }
2.2.6 popcount
cpp 复制代码
ll count(ll x){ return __builtin_popcountll(x); }
int count(int x){ return __builtin_popcount(x); }
2.2.7 <math xmlns="http://www.w3.org/1998/Math/MathML"> ϕ ( n ) \phi(n) </math>ϕ(n)

欧拉函数 <math xmlns="http://www.w3.org/1998/Math/MathML"> ϕ ( n ) = ∑ i = 1 n [ gcd ⁡ ( i , n ) = 1 ] \phi(n)=\sum_{i=1}^{n}[\operatorname{gcd}(i,n)=1] </math>ϕ(n)=∑i=1n[gcd(i,n)=1].

由容斥原理可推出: <math xmlns="http://www.w3.org/1998/Math/MathML"> n = p 1 α 1 ⋅ p 2 α 2 ⋯ p j α j    ⟹    ϕ ( n ) = n ⋅ ∏ i = 1 j ( 1 − p i − 1 ) = ( p 1 − 1 ) ( p 2 − 1 ) ⋯ ( p j − 1 ) ⋅ p 1 α 1 − 1 ⋅ p 2 α 2 − 1 ⋯ p j α j − 1 n=p_1^{\alpha_1}\cdot p_2^{\alpha_2}\cdots p_j^{\alpha_j}\implies \phi(n)=n\cdot \prod_{i=1}^{j}(1-p_{i}^{-1}) =(p_1-1)(p_2-1)\cdots(p_j-1)\cdot p_1^{\alpha_1-1}\cdot p_2^{\alpha_2-1}\cdots p_j^{\alpha_j-1} </math>n=p1α1⋅p2α2⋯pjαj⟹ϕ(n)=n⋅∏i=1j(1−pi−1)=(p1−1)(p2−1)⋯(pj−1)⋅p1α1−1⋅p2α2−1⋯pjαj−1. 且 若 <math xmlns="http://www.w3.org/1998/Math/MathML"> p p </math>p 为素数,有 <math xmlns="http://www.w3.org/1998/Math/MathML"> ϕ ( p ) = p − 1 \phi(p)=p-1 </math>ϕ(p)=p−1.

可以在 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( log ⁡ n ) O(\log n) </math>O(logn) 求单点欧拉函数,可以在 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n) 递推求 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 </math>1 到 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 欧拉函数.

cpp 复制代码
// $O(\log n)$ 求单点欧拉函数
ll get_phi(ll x){
	ll phi=1;
	for(ll i=2;i<=x/i;i++){
		if(x%i==0){
			phi*=(i-1);
			x/=i;
			while(x%i==0) phi*=i,x/=i;
		}
	}
	if(x>1) phi*=(x-1);
	return phi;
}
// $O(n)$  递推求 $1$ 到 $n$ 欧拉函数
bool st[N];
vi primes;
ll phi[N];
void get_phi(ll maxn){
	phi[1]=1;
	for(ll i=2;i<=maxn;i++){
		if(!st[i]) primes.pb(i),phi[i]=i-1;
		for(ll j:primes){
			if(j>maxn/i) break;
			st[i*j]=1;
			if(i%j==0) { phi[i*j]=phi[i]*j; break; }
			phi[i*j]=phi[i]*(j-1);
		}
	}
}
2.2.8 <math xmlns="http://www.w3.org/1998/Math/MathML"> a ⋅ a − 1 ≡ 1 ( mod ⁡ p ) a\cdot a^{-1}\equiv 1(\operatorname{mod} p) </math>a⋅a−1≡1(modp)

单点求乘法逆元:可以直接解不定方程, <math xmlns="http://www.w3.org/1998/Math/MathML"> a b ≡ 1 ( mod ⁡ p )    ⟺    a b = m p + 1    ⟺    a b − m p = 1 ab\equiv 1(\operatorname{mod} p) \iff ab=mp+1 \iff ab-mp=1 </math>ab≡1(modp)⟺ab=mp+1⟺ab−mp=1,有解的充要条件是 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( a , p ) = 1 (a,p)=1 </math>(a,p)=1. 也可以由欧拉定理 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( n , a ) = 1    ⟹    a ϕ ( n ) ≡ 1 ( mod ⁡ n ) (n,a)=1 \implies a^{\phi(n)}\equiv 1(\operatorname{mod} n) </math>(n,a)=1⟹aϕ(n)≡1(modn),特别的,若 <math xmlns="http://www.w3.org/1998/Math/MathML"> p p </math>p 为素数,则 <math xmlns="http://www.w3.org/1998/Math/MathML"> a p − 1 ≡ 1 ( mod ⁡ p ) a^{p-1}\equiv 1(\operatorname{mod} p) </math>ap−1≡1(modp).

递推求 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 </math>1 到 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 的乘法逆元:求 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i 的逆元,考虑 <math xmlns="http://www.w3.org/1998/Math/MathML"> p = ⌊ p i ⌋ ⋅ i + p % i ≡ 0 ( mod ⁡ p ) p=\left\lfloor \frac{p}{i} \right\rfloor\cdot i+p \% i\equiv 0(\operatorname{mod} p) </math>p=⌊ip⌋⋅i+p%i≡0(modp),其中注意到 <math xmlns="http://www.w3.org/1998/Math/MathML"> p % i < i p\%i<i </math>p%i<i,于是可以递推。 <math xmlns="http://www.w3.org/1998/Math/MathML"> ⌊ p i ⌋ ⋅ i ≡ − ( p % i )    ⟺    i − 1 ≡ − ( p % i ) − 1 ⋅ ⌊ p i ⌋ ( mod ⁡ p ) \left\lfloor \frac{p}{i} \right\rfloor\cdot i\equiv -(p\%i) \iff i^{-1}\equiv -(p\%i)^{-1}\cdot \left\lfloor \frac{p}{i} \right\rfloor(\operatorname{mod} p) </math>⌊ip⌋⋅i≡−(p%i)⟺i−1≡−(p%i)−1⋅⌊ip⌋(modp).

2.2.9 extended eular theorem

欧拉定理: <math xmlns="http://www.w3.org/1998/Math/MathML"> ( a , m ) = 1    ⟹    a ϕ ( m ) ≡ 1 ( mod ⁡ m ) (a,m)=1\implies a^{\phi(m)}\equiv 1(\operatorname{mod} m) </math>(a,m)=1⟹aϕ(m)≡1(modm) 扩展欧拉定理: <math xmlns="http://www.w3.org/1998/Math/MathML"> a c ≡ a c % ϕ ( m ) + ϕ ( m ) ( mod ⁡ m ) if c ≥ ϕ ( m ) a^{c}\equiv a^{c\%\phi(m)+\phi(m)}(\operatorname{mod} m) \text{if} c\ge \phi(m) </math>ac≡ac%ϕ(m)+ϕ(m)(modm)ifc≥ϕ(m),在这里不要求 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( a , m ) = 1 (a,m)=1 </math>(a,m)=1

2.2.10 linear mod equation system

中国剩余定理 和 两两相消。 考虑方程组
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> { x ≡ a 1 ( mod ⁡ m 1 ) x ≡ a 2 ( mod ⁡ m 2 ) ⋯ x ≡ a k ( mod ⁡ m k ) \begin{cases} x \equiv a_1(\operatorname{mod} m_1) \\ x \equiv a_2(\operatorname{mod} m_2) \\ \cdots \\ x \equiv a_k(\operatorname{mod} m_k) \end{cases} </math>⎩ ⎨ ⎧x≡a1(modm1)x≡a2(modm2)⋯x≡ak(modmk)

中国剩余定理:如果 <math xmlns="http://www.w3.org/1998/Math/MathML"> m 1 , m 2 , ... , m k m_1,m_2, \ldots ,m_k </math>m1,m2,...,mk 两两互素,则有 <math xmlns="http://www.w3.org/1998/Math/MathML"> x ≡ ∑ i = 1 k M i ′ M i a i ( mod ⁡ M ) x\equiv \sum_{i=1}^{k}M_i' M_i a_i(\operatorname{mod} M) </math>x≡∑i=1kMi′Miai(modM),其中, <math xmlns="http://www.w3.org/1998/Math/MathML"> M = ∏ i = 1 k m i M=\prod_{i=1}^{k} m_i </math>M=∏i=1kmi, <math xmlns="http://www.w3.org/1998/Math/MathML"> M i = M / m i M_i=M / m_i </math>Mi=M/mi, <math xmlns="http://www.w3.org/1998/Math/MathML"> M i ′ M i ≡ 1 ( mod ⁡ m i ) M_i' M_i\equiv 1(\operatorname{mod} m_i) </math>Mi′Mi≡1(modmi)

2.2.11 Inclusion-Exclusion principle

最简单的形式,便于理解:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> ∣ S − A ∪ B ∣ = ∣ S ∣ − ∣ A ∣ − ∣ B ∣ + ∣ A ∩ B ∣ \left\vert S-A \cup B \right\vert=\left\vert S \right\vert - \left\vert A \right\vert -\left\vert B \right\vert +\left\vert A \cap B \right\vert </math>∣S−A∪B∣=∣S∣−∣A∣−∣B∣+∣A∩B∣

推广:我们将满足某种性质记作 <math xmlns="http://www.w3.org/1998/Math/MathML"> a i a_i </math>ai,不满足某种性质记作 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 − a i 1-a_i </math>1−ai,则有
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> N ( ( 1 − a 1 ) ( 1 − a 2 ) ⋯ ( 1 − a n ) ) = ∑ k = 0 n ( − 1 ) k ∑ 1 ≤ j 1 ≤ ⋯ ≤ j k ≤ n N ( a j 1 ⋯ a j k ) N((1-a_1)(1-a_2)\cdots (1-a_n))=\sum_{k=0}^{n}(-1)^{k}\sum_{1\le j_1\le \cdots\le j_k\le n}N(a_{j_1}\cdots a_{j_k}) </math>N((1−a1)(1−a2)⋯(1−an))=k=0∑n(−1)k1≤j1≤⋯≤jk≤n∑N(aj1⋯ajk)

如果选 <math xmlns="http://www.w3.org/1998/Math/MathML"> k k </math>k 种性质进行容斥是相互等价的,还可以写成:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> N ( ( 1 − a 1 ) ( 1 − a 2 ) ⋯ ( 1 − a n ) ) = ∑ k = 0 n ( − 1 ) k ( n k ) N ( a 1 a 2 ⋯ a k ) N((1-a_1)(1-a_2)\cdots (1-a_n))=\sum_{k=0}^{n}(-1)^{k}\binom{n}{k}N(a_1a_2\cdots a_k) </math>N((1−a1)(1−a2)⋯(1−an))=k=0∑n(−1)k(kn)N(a1a2⋯ak)

可以考虑 dp ,如果要枚举集合可以使用 dfs,注意记录 <math xmlns="http://www.w3.org/1998/Math/MathML"> − 1 -1 </math>−1 的符号

2.2.12 multiplicative function

积性函数:若对于 <math xmlns="http://www.w3.org/1998/Math/MathML"> f ( x ) f(x) </math>f(x),有 <math xmlns="http://www.w3.org/1998/Math/MathML"> p ⊥ q    ⟹    f ( p q ) = f ( p ) f ( q ) p \bot q \implies f(pq)=f(p)f(q) </math>p⊥q⟹f(pq)=f(p)f(q),则称 <math xmlns="http://www.w3.org/1998/Math/MathML"> f f </math>f 为积性函数

如果不要求 <math xmlns="http://www.w3.org/1998/Math/MathML"> p ⊥ q p \bot q </math>p⊥q,则称为完全积性函数

对于积性函数,可以利用欧拉筛, <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n) 递推他们的值

cpp 复制代码
// 完全积性函数
bool st[N];
vi primes;
ll f[N];
void ss(int maxn){
    for(int i=2;i<=maxn;i++){
        if(!st[i]) primes.pb(i),f[i]=initial_value(i);
        for(int j:primes){
          if(j>maxn/i) break;
          st[i*j]=1,f[i*j]=f[i]*f[j];
          if(i%j==0) break;
      }
    }
}
// 求 p \bot q 的积性函数
// 单点求
ll get_f(ll n){
	ll ans=1;
	for(int i=2;i<=n/i;i++){
		int cnt=0;
		while(n%i==0) cnt++,n/=i;
		ans=ans*f(i,cnt)%mod; // f(p,k)=f(p^k)
	}
	if(n>1) ans=ans*f(n,1)%mod;
	return ans;
}
// 也可以利用最小的质数来递推 1 ~ n
// cnt[] 记录最小质数出现的次数
bool st[N];
vi primes;
ll f[N],cnt[N];
void ss(int maxn){
	f[1]=1;
    for(int i=2;i<=maxn;i++){
        if(!st[i]) primes.pb(i),cnt[i]=1,f[i]=calc_f(i,1);
        for(int j:primes){
            if(j>maxn/i) break;
            st[i*j]=1;
            if(i%j==0){
                cnt[i*j]=cnt[i]+1;
                f[i*j]=f[i]/calc_f(j,cnt[i])*calc_f(j,cnt[i]+1);
                break;
            }
            cnt[i*j]=1;
            f[i*j]=f[i]*calc_f(j,1);
      }
    }
}
2.2.13 Möbius inversion

对于数论函数,常见的两种莫比乌斯反演的两种形式:

  • 对因子反演: <math xmlns="http://www.w3.org/1998/Math/MathML"> f ( n ) = ∑ d ∣ n g ( d )    ⟺    g ( n ) = ∑ d ∣ n μ ( n d ) f ( d ) = ∑ d ∣ n μ ( d ) f ( n d ) f(n)=\sum_{d \mid n}g(d) \iff g(n)=\sum_{d \mid n} \mu(\frac{n}{d})f(d)=\sum_{d \mid n} \mu(d)f(\frac{n}{d}) </math>f(n)=∑d∣ng(d)⟺g(n)=∑d∣nμ(dn)f(d)=∑d∣nμ(d)f(dn) (后面的等号是由于因数的成对出现)
  • 对倍数反演: <math xmlns="http://www.w3.org/1998/Math/MathML"> f ( d ) = ∑ d ∣ n , n ≤ N g ( n )    ⟺    g ( d ) = ∑ d ∣ n , n ≤ N μ ( n d ) f ( n ) f(d)=\sum_{d \mid n , n\le N}g(n) \iff g(d)=\sum_{d \mid n, n\le N}\mu(\frac{n}{d})f(n) </math>f(d)=∑d∣n,n≤Ng(n)⟺g(d)=∑d∣n,n≤Nμ(dn)f(n)

本质是在整除的意义上划分出的集合上进行容斥 。其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> μ \mu </math>μ 为莫比乌斯函数:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> μ ( 1 ) = 1 \mu(1)=1 </math>μ(1)=1
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> x = p 1 p 2 ⋯ p k    ⟹    μ ( x ) = ( − 1 ) k x=p_1 p_2 \cdots p_k \implies \mu(x)=(-1)^{k} </math>x=p1p2⋯pk⟹μ(x)=(−1)k
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> x = p 1 α 1 p 2 α 2 ⋯ p k α k    ⟹    μ ( x ) = 0 x=p_1^{\alpha_1}p_2^{\alpha_2}\cdots p_k^{\alpha_k} \implies \mu(x)=0 </math>x=p1α1p2α2⋯pkαk⟹μ(x)=0

<math xmlns="http://www.w3.org/1998/Math/MathML"> μ \mu </math>μ 为积性函数,利用欧拉筛可以 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n) 递推求

cpp 复制代码
bool st[N];
vi primes;
int mu[N];
void get_mu(int maxn){
	mu[1]=1;
    for(int i=2;i<=maxn;i++){
        if(!st[i]) primes.pb(i),mu[i]=-1;
        for(int j:primes){
            if(j>maxn/i) break;
            st[i*j]=1;
            if(i%j==0){ mu[i*j]=0; break; }
            mu[i*j]=-mu[i];
      }
    }
}

一般单项不好求,但是如果对于倍数的式子相加,或者因数的式子相加的和(就是考虑一个集合的时候)好求,可以考虑整体求,然后对求和的函数进行反演。

2.2.14 Dirichlet convolution

设 <math xmlns="http://www.w3.org/1998/Math/MathML"> f  ⁣ : N → R f\colon \mathbb{N} \to \mathbb{R} </math>f:N→R, <math xmlns="http://www.w3.org/1998/Math/MathML"> g  ⁣ : N → R g\colon \mathbb{N} \to \mathbb{R} </math>g:N→R,则定义他们的狄利克雷卷积为 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( n d ) (f * g)(n)=\sum_{d \mid n}f(d)g(\frac{n}{d}) </math>(f∗g)(n)=∑d∣nf(d)g(dn).

若 <math xmlns="http://www.w3.org/1998/Math/MathML"> f f </math>f 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> g g </math>g 为积性函数,则他们的卷积也为积性函数,且满足交换律,结合律。

为了方便,我们定义如下函数:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 ( n ) = 1 1(n)=1 </math>1(n)=1,在狄利克雷卷积的乘法中与 <math xmlns="http://www.w3.org/1998/Math/MathML"> μ \mu </math>μ 互为逆元
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> ϵ ( n ) = [ n = 1 ] \epsilon(n)=[n=1] </math>ϵ(n)=[n=1],狄利克雷卷积的乘法单位元
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> id ( n ) = n \text{id}(n)=n </math>id(n)=n

于是,我们有:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> f = g ∗ 1    ⟺    g = f ∗ μ f=g*1 \iff g=f*\mu </math>f=g∗1⟺g=f∗μ (aka. Möbius inversion)
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> ϵ = μ ∗ 1    ⟺    μ = ϵ ∗ μ \epsilon = \mu * 1 \iff \mu=\epsilon*\mu </math>ϵ=μ∗1⟺μ=ϵ∗μ,证明可以考虑右侧反演单位元或者左侧的话其实就是 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( 1 + ( − 1 ) ) k (1+(-1))^{k} </math>(1+(−1))k 的二项式展开
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> id = ϕ ∗ 1    ⟺    ϕ = id ∗ μ \text{id}=\phi * 1 \iff \phi = \text{id} * \mu </math>id=ϕ∗1⟺ϕ=id∗μ

一些技巧:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> ∑ i = 1 n i ⋅ [ i ⊥ n ] = 1 2 ( n ϕ ( n ) + ϵ ( n ) ) \sum_{i=1}^{n}i\cdot [i \bot n]=\frac{1}{2}(n\phi(n)+\epsilon(n)) </math>∑i=1ni⋅[i⊥n]=21(nϕ(n)+ϵ(n)) Proof : 考虑到 <math xmlns="http://www.w3.org/1998/Math/MathML"> gcd ⁡ ( i , n ) = gcd ⁡ ( n − i , n ) \operatorname{gcd}(i,n)=\operatorname{gcd}(n-i,n) </math>gcd(i,n)=gcd(n−i,n),所以他们是成对出现的,一共的对数就是 <math xmlns="http://www.w3.org/1998/Math/MathML"> ϕ ( n ) \phi(n) </math>ϕ(n),每一对贡献的和是 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n,特判 <math xmlns="http://www.w3.org/1998/Math/MathML"> n = 1 n=1 </math>n=1 的情况。
2.2.15 matrix multiplication

可以用来加速 线性 dp 的递推。 数据结构中,将维护值扩展成成维护矩阵。

<math xmlns="http://www.w3.org/1998/Math/MathML"> A ∈ M n × t ( R ) A \in M_{n \times t}(\mathbb{R}) </math>A∈Mn×t(R), <math xmlns="http://www.w3.org/1998/Math/MathML"> B ∈ M t × m ( R ) B\in M_{t\times m}(\mathbb{R}) </math>B∈Mt×m(R),那么 <math xmlns="http://www.w3.org/1998/Math/MathML"> A B [ i , j ] = ∑ k = 1 t A [ i , k ] ⋅ B [ k , m ] AB[i,j]=\sum_{k=1}^{t}A[i,k]\cdot B[k,m] </math>AB[i,j]=∑k=1tA[i,k]⋅B[k,m].

cpp 复制代码
const int N=105;
const ll mod=1e9+7;
template<class T>
struct mat{
	int n,m;    // 0~n-1, 0~m-1
	T a[N][N];
	mat(int n,int m) { this->n=n,this->m=m; memset(a, 0, sizeof a); }
    T* operator[](int x) { return a[x]; }
    const T* operator[](int x) const { return a[x]; }
    mat operator-(const mat &rhs) const {
        mat<T> res(n,m);
        for(int i=0;i<n;i++) for(int j=0;j<m;j++)
            res[i][j]=(a[i][j]+mod-rhs[i][j])%mod;
        return res;
    }
    mat operator+(const mat &rhs) const {
        mat<T> res(n,m);
        for(int i=0;i<n;i++) for(int j=0;j<m;j++)
            res[i][j]=(a[i][j]+rhs[i][j])%mod;
        return res;
    }
    mat operator*(const mat &rhs) const {
    	// assert(m==rhs.n);
        mat<T> res(n,rhs.m);
		for(int i=0;i<n;i++) for(int j=0;j<rhs.m;j++) for(int k=0;k<m;k++)
			res[i][j]+=a[i][k]*rhs[k][j], res[i][j]%=mod;
        return res;
    }
    mat qmi(int k) {
    	// assert(n==m);
        mat<T> res(n, n), t=*this;
        for(int i=0;i<n;i++) res[i][i]=1;
        for(;k;t=t*t,k>>=1) if(k&1) res=res*t;
        return res;
    }
};
2.2.16 Gauss elimination

线性方程组 <math xmlns="http://www.w3.org/1998/Math/MathML"> A x = b Ax=b </math>Ax=b 的解。设 <math xmlns="http://www.w3.org/1998/Math/MathML"> A A </math>A 的增广矩阵记作 <math xmlns="http://www.w3.org/1998/Math/MathML"> A ~ = [ A ∣ b ] \tilde{A}=[A \mid b] </math>A~=[A∣b],将解集记作 <math xmlns="http://www.w3.org/1998/Math/MathML"> S = { x ∣ A x = b } S=\{ x \mid Ax=b \} </math>S={x∣Ax=b},则有

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> ∣ S ∣ = 0    ⟺    rank ⁡ A < rank ⁡ A ~ \left\vert S \right\vert =0 \iff \operatorname{rank}A<\operatorname{rank}\tilde{A} </math>∣S∣=0⟺rankA<rankA~
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> ∣ S ∣ = 1    ⟺    rank ⁡ A = rank ⁡ A ~ \left\vert S \right\vert =1\iff \operatorname{rank}A=\operatorname{rank}\tilde{A} </math>∣S∣=1⟺rankA=rankA~
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> ∣ S ∣ = ℵ 1    ⟺    rank ⁡ A > rank ⁡ A ~ \left\vert S \right\vert = \aleph_1 \iff \operatorname{rank}A>\operatorname{rank}\tilde{A} </math>∣S∣=ℵ1⟺rankA>rankA~
cpp 复制代码
constexpr int N=105;
constexpr double eps=1e-6;
template<class T=double>
struct gmat{
	int n,m;	// 0~n-1, 0~m-1
	T a[N][N];
	gmat(int n,int m) { this->n=n,this->m=m; memset(a, 0, sizeof a); }
    T* operator[](int x) { return a[x]; }
    const T* operator[](int x) const { return a[x]; }
    // 0: no solution || 1: one solution || -1: inf solution
	int gauss(){
		int c,r;
		for(c=0,r=0;c<n;c++){
			int t=r;
			for(int i=r+1;i<n;i++) if(fabs(a[t][c])<fabs(a[i][c])) t=i;
			if(fabs(a[t][c])<eps) continue;
			for(int i=c;i<m;i++) swap(a[t][i],a[r][i]);
			for(int i=m-1;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=m-1;j>=c;j--) a[i][j]-=a[i][c]*a[r][j];
			r++;
		}
		if(r<n){
			for(int i=r;i<n;i++) if(fabs(a[i][m-1])>eps) return 0;
			return -1;
		}
		for(int i=n-1;i>=0;i--) for(int j=0;j<i;j++) a[j][m-1]-=a[i][m-1]*a[j][i];
		return 1;
	}
};

求解异或方程组 在时间复杂度要求不严格的情况下,可以使用 bit 结构体:

cpp 复制代码
// 记得修改 gauss 中关于精度的判断
struct bit {
    bool val;
    bit(bool val=0):val(val) {}
    bit operator+(const bit& x) const { return bit(val^x.val); }
    bit operator-(const bit& x) const { return bit(val^x.val); }
    void operator-=(const bit& x) { val^=x.val; }
    bit operator*(const bit& x) const { return bit(val&x.val); }
    bit operator/(const bit& x) const { return bit(val); }
    void operator/=(const bit& x) { val=val/x.val; }
    bool operator<(const bit& x) const { return !val&&x.val; }
    bool operator==(const int x) const { return val==x; }
    bool operator!=(const int x) const { return !(*this==x); }
    operator bool() const { return val; }
    friend istream& operator>>(istream& in,bit& b){ return in>>b.val,in; }
    friend ostream& operator<<(ostream& out,const bit& b){ return out<<b.val,out; }
};

或者,使用 bitset 优化

cpp 复制代码
struct bmat{
    int n,m;

}
2.2.27 linear basis

布尔域 <math xmlns="http://www.w3.org/1998/Math/MathML"> Z 2 \mathbb{Z}_{2} </math>Z2 和 异或(加法),逻辑与(数乘)构成线性空间,其中的极大线性无关组称为线性基。 <math xmlns="http://www.w3.org/1998/Math/MathML"> p [ i ] p[i] </math>p[i] 表示最高位是 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i 位的基向量。

cpp 复制代码
typedef unsigned long long ull;
constexpr int N=105;
constexpr int B=50;
int rk=0;
ull p[N];
void insert(ull x){
	for(int i=B;i>=0;i--){
		if(!(x>>i&1)) continue;
		if(!p[i]) return p[i]=x,void();
		x^=p[i];
	}
}

references

相关推荐
仪器科学与传感技术博士3 分钟前
python:如何调节机器学习算法的鲁棒性,以支持向量机SVM为例,让伙伴们看的更明白
python·算法·机器学习
幻风_huanfeng4 分钟前
自然语言理解领域算法模型演进图谱
算法
yuyousheng21 分钟前
C语言使用GmSSL库实现sm3、sm4算法
c语言·算法·哈希算法
菜就多练,以前是以前,现在是现在33 分钟前
Codeforces Round 986 (Div. 2)
c++·算法
瓦特what?1 小时前
C + +
c语言·开发语言·c++·经验分享·笔记·算法·程序员创富
啊阿狸不会拉杆2 小时前
《算法导论》第 1 章 - 算法在计算中的作用
开发语言·数据结构·c++·算法·排序算法
WBluuue2 小时前
数据结构与算法:哈希函数的应用及一些工程算法
c++·算法·面试·哈希算法
刃神太酷啦2 小时前
C++ 容器适配器与核心数据结构精解:栈、队列、deque 底层实现与实战应用----《Hello C++ Wrold!》(17)--(C/C++)
java·c语言·数据结构·c++·qt·算法·leetcode
阑梦清川2 小时前
算法竞赛---宽度优先搜索求解最短路径问题
算法