不时更新常用的模板,模板可能写的有些早,不像现在写的一样
数论
组合数递推公式
1 C[1][0] = C[1][1] = 1; 2 for (int i=2; i<=N; i++) 3 { 4 C[i][0] = 1; 5 for (int j=1; j<=N; j++) 6 C[i][j] = C[i-1][j]+C[i-1][j-1]; 7 }
求逆元
a扩展欧几里得求逆元
1 #include<cstdio> 2 3 int exgcd(int a,int b,int &x,int &y) 4 { 5 if (b==0) 6 { 7 x = 1; 8 y = 0; 9 return a; 10 } 11 int r = exgcd(b,a%b,x,y); 12 int tmp = x; 13 x = y; 14 y = tmp-a/b*y; 15 return r; 16 } 17 18 int main() 19 { 20 //gcd(a,p)==1 21 int a,p,r,x,y; 22 while (scanf("%d%d",&a,&p)!=EOF) 23 { 24 r = exgcd(a,p,x,y); 25 printf("%d",(x%p+p)%p); 26 } 27 return 0; 28 }
b线性求逆元
1 int inv[MAXN]; 2 void INV() //线性求到a的逆元 3 { 4 inv[1] = 1; 5 for (int i=2; i<=n; ++i) { 6 inv[i] = (1ll*(-(p/i))*inv[p%i])%p; 7 inv[i] = (inv[i]+p)%p; 8 } 9 } 10 11 /*-----------------------------------------------*/ 12 13 int INV(int a)//线性求a的逆元,可以记忆化 14 { 15 if (a==1) return 1; 16 return ((-(p/a)*INV(p%a))%p); 17 }
c线性求阶乘的逆元
/* 假设知道了模p下a阶乘的逆元b,fac[a] * b ≡ 1 (mod p) 那么a-1的阶乘的逆元就是,fac[a-1] * a * b ≡ 1 (mod p) 所以 b * a 就是a-1的阶乘的逆元。 */ ifac[1000000] = ksm(1000000, mod - 2); for (int i=1000000; i>=1; --i) ifac[i - 1] = ifac[i] * i % mod;
中国剩余定理51nod1079
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline LL read() { 6 LL x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 7 for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 8 } 9 10 11 LL a[100], m[100]; 12 13 LL inv(LL a,LL b,LL p) { 14 LL res = 1; 15 while (b) { 16 if (b & 1) res = res * a % p; 17 a = a * a % p; 18 b >>= 1; 19 } 20 return res; 21 } 22 23 int main() { 24 25 int n;scanf("%d",&n); 26 LL M = 1; 27 28 for (int i=1; i<=n; ++i) { 29 m[i] = read(); 30 a[i] = read(); 31 M = M * m[i]; 32 } 33 34 35 LL Ans = 0; 36 for (int i=1; i<=n; ++i) { 37 LL Mi = M / m[i]; 38 LL T = inv(Mi,m[i]-2,m[i]); 39 Ans = (Ans + a[i] * T * Mi) % M; 40 } 41 cout << (Ans % M + M) % M; 42 return 0; 43 }
扩展中国剩余定理POJ2891
1 #include<cstdio> 2 #include<cctype> 3 using namespace std; 4 typedef long long LL; 5 6 inline int read() { 7 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 8 for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 9 } 10 11 LL gcd(LL a, LL b) { 12 return b == 0 ? a : gcd(b, a%b); 13 } 14 15 void exgcd(LL a,LL b,LL &x,LL &y) { 16 if (b == 0) { 17 x = 1,b = 0; 18 return ; 19 } 20 exgcd(b,a%b,x,y); 21 LL t = x; 22 x = y; 23 y = t - a / b * y; 24 } 25 26 LL inv(LL a,LL b) { 27 LL x = 0,y = 0; 28 exgcd(a,b,x,y); 29 x = (x % b + b) % b; 30 while (x <= 0) x += b; 31 return x; 32 } 33 34 LL m[1010],a[1010]; 35 36 int main() { 37 int n; 38 while (scanf("%d",&n) != EOF) { 39 bool flag = true; 40 for (int i=1; i<=n; ++i) { 41 scanf("%lld%lld",&m[i],&a[i]); 42 } 43 LL m1,m2,a1,a2,c,d; 44 for (int i=2; i<=n; ++i) { 45 m1 = m[i-1], m2 = m[i], a1 = a[i-1], a2 = a[i], c = a2 - a1; 46 d = gcd(m1, m2); 47 if (c % d) {flag = false;break;} 48 m[i] = m1 * m2 / d; 49 a[i] = inv(m1/d, m2/d) * (c / d) % (m2 / d) * m1 + a1; 50 a[i] = (a[i] % m[i] + m[i]) % m[i]; 51 } 52 if (!flag) puts("-1"); 53 else printf("%lld ",a[n]); 54 } 55 return 0; 56 }
矩阵乘法求斐波那契,矩阵快速幂(第一项是1,第二项是1)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 5 using namespace std; 6 7 const int mod = 1e9+7; 8 const int N = 2; 9 10 struct Matrix{ 11 int a[N][N]; 12 Matrix(){ 13 this->clear(); 14 } 15 void clear(){ 16 memset(a,0,sizeof(a)); 17 } 18 void setone(){ 19 this->clear(); 20 for (int i=0; i<N; ++i) 21 a[i][i] = 1; 22 } 23 Matrix operator * (const Matrix &x) const 24 { 25 Matrix c; 26 for (int k=0; k<N; k++) 27 for (int i=0; i<N; ++i) 28 for (int j=0; j<N; ++j) 29 c.a[i][j] = (c.a[i][j]+1ll*a[i][k]*x.a[k][j])%mod; 30 return c; 31 } 32 }; 33 34 int fibn(int n) 35 { 36 Matrix x,s; 37 x.a[0][0] = x.a[0][1] = x.a[1][0] = 1; 38 s.setone(); 39 for (; n; n>>=1) 40 { 41 if (n&1) s = s*x; 42 x = x*x; 43 } 44 return (s.a[0][0]+s.a[0][1])%mod; 45 } 46 int main() 47 { 48 int n; 49 while (~scanf("%d",&n)) 50 { 51 if (n==1||n==2) puts("1"); 52 else printf("%d ",fibn(n-2)); 53 } 54 return 0; 55 }
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 using namespace std; 5 6 const int mod = 1e9+7; 7 const int N = 2; 8 9 struct Matrix{ 10 int a[N][N]; 11 Matrix () {memset(a,0,sizeof(a));} 12 }t; 13 Matrix mul(Matrix a,Matrix b) { 14 Matrix c; 15 for (int k=0; k<N; k++) 16 for (int i=0; i<N; ++i) 17 for (int j=0; j<N; ++j) 18 c.a[i][j] = (c.a[i][j]+1ll*a.a[i][k]*b.a[k][j])%mod; 19 return c; 20 } 21 int fibn(int n) { 22 Matrix x,s; 23 x.a[0][0] = x.a[0][1] = x.a[1][0] = 1; 24 s.a[0][0] = s.a[1][1] = 1; 25 while (n) { 26 if (n&1) s = mul(s,x); 27 x = mul(x,x); 28 n >>= 1; 29 } 30 return (s.a[0][0]+s.a[0][1])%mod; 31 } 32 int main() { 33 int n; 34 while (~scanf("%d",&n)) { 35 if (n==1||n==2) puts("1"); 36 else printf("%d ",fibn(n-2)); 37 } 38 return 0; 39 }
线性筛素数O(n)
1 for (int i=2; i<=N; i++) { 2 if (!noprime[i]) { 3 prime[++tot]=i; 4 } 5 for (int j=1; j<=tot&&i*prime[j]<=N; j++) { 6 noprime[i*prime[j]] = true; 7 if(i % prime[j] == 0) break ; 8 } 9 }
线性筛欧拉函数
1 for (int i=2; i<=N; i++) { 2 if (!noprime[i]) { 3 prime[++tot]=i; 4 phi[i] = i-1; 5 } 6 for (int j=1; j<=tot&&i*prime[j]<=N; j++) { 7 noprime[i*prime[j]] = true; 8 if(i % prime[j] == 0) { 9 phi[i * prime[j]] = phi[i] * prime[j]; 10 break ; //重要 11 } 12 else phi[i * prime[j]] = phi[i]*(prime[j]-1); 13 } 14 }
线性筛莫比乌斯函数
1 void getmu() { 2 mu[1] = 1; 3 for (int i=2; i<=N; ++i) { 4 if (!noprime[i]) prime[++tot] = i,mu[i] = -1; 5 for (int j=1; j<=tot&&i*prime[j]<=N; ++j) { 6 noprime[i * prime[j]] = true; 7 if (i % prime[j] == 0) {mu[i * prime[j]] = 0; break;} 8 mu[i * prime[j]] = - mu[i]; 9 } 10 } 11 }
求组合数(很大!)
一般的逆元求解
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1000000; 4 const int mod=1000000007; 5 6 int f[maxn+10]; 7 void init(){//阶乘 8 f[0]=1; 9 for(int i=1;i<=maxn;i++){ 10 f[i]=1ll*f[i-1]*i%mod; 11 } 12 } 13 14 int fast(int a,int n){ 15 if (n==0) return 1; 16 if (n%2) return 1ll*a*fast(a,n-1)%mod; 17 int tmp=fast(a,n/2); 18 return 1ll*tmp*tmp%mod; 19 } 20 21 int C(int n,int m){ 22 if(n==m||m==0)return 1; 23 return (1ll*f[n]*fast(f[m],mod-2)%mod)*fast(f[n-m],mod-2)%mod; 24 } 25 26 int main(){ 27 init(); 28 int n,m,k; 29 scanf("%d%d%d",&n,&m,&k); 30 int x = n-k,y = m-1; 31 printf("%d ",C(x,y)); 32 return 0; 33 }
Lucas定理
1 //适用于p很小,n,m很大 或者 n,m不大但大于p 2 #include<cstdio> 3 4 typedef long long LL; 5 const int N = 1000010; 6 7 LL n,m,p,f[N]; 8 9 void init(int x) { 10 f[0] = 1; 11 for (int i=1; i<=x; ++i) f[i] = (i * f[i-1]) % x; 12 } 13 LL ksm(LL a,LL b) { 14 LL ans = 1; 15 while (b) { 16 if (b & 1) ans = (ans * a) % p; 17 b >>= 1; 18 a = (a * a) % p; 19 } 20 return ans; 21 } 22 LL C(LL n,LL m) { 23 if (m > n) return 0; 24 return (f[n] * ksm(f[m],p-2)) % p * ksm(f[n-m],p-2) % p; 25 } 26 LL Lucas(LL n,LL m) { 27 if (m == 0) return 1; 28 else return (C(n%p,m%p) * Lucas(n/p,m/p)) % p; 29 } 30 int main() { 31 int T; 32 scanf("%d",&T); 33 while (T--) { 34 scanf("%lld%lld%lld",&n,&m,&p); 35 init(p); 36 printf("%lld ",Lucas(n,m)); 37 } 38 return 0; 39 }
快速幂
1 int ksm(int a,int b,int p) { 2 int ret = 1; 3 while (b) { 4 if (b & 1) ret = (1ll*ret*a) % p; 5 a = (1ll*a*a)%p; 6 b >>= 1; 7 } 8 return ret%p; 9 }
快速乘
1 int ksc(int a,int b,int p) { 2 int ret = 0; 3 while (b) { 4 if (b & 1) ret = (ret+a)%p; 5 a = (a+a)%p; 6 b >>= 1; 7 } 8 return ret; 9 }
素数判定Miller_Rabin
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<ctime> 5 6 using namespace std; 7 8 typedef long long LL; 9 10 LL ksm(LL a,LL b,LL p) { 11 LL ans = 1; 12 a = a % p; 13 while (b) { 14 if (b & 1) ans = (ans * a) % p; 15 a = (a * a) % p; 16 b >>= 1; 17 } 18 return ans; 19 } 20 bool witness(LL a,LL n,LL d,LL r) { 21 LL ret = ksm(a,d,n); 22 LL last = ret; 23 while (r--) { 24 ret = ret * ret % n; 25 if (ret==1 && last!=1 && last!=n-1) return false; 26 last = ret; 27 } 28 if (ret != 1) return false; 29 return true; 30 } 31 bool miller_rabin(LL n) { 32 if (n==2) return true; 33 if (n==1 || (n&1)==0) return false; 34 LL d = n - 1,r = 0; 35 while ((d&1)==0) r++,d>>=1; 36 for (LL i=1; i<=20; ++i) { 37 LL a = rand()%(n-1)+1; 38 if (!witness(a,n,d,r)) return false; 39 } 40 return true; 41 } 42 int main () { 43 srand((unsigned)time(NULL)); 44 LL a,b; 45 while (cin >> a) { 46 if (miller_rabin(a)) cout << "yes "; 47 else cout << "no "; 48 } 49 return 0; 50 }
FFT
递归
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 7 using namespace std; 8 const int N = 300100; 9 const double eps = 1e-8; 10 const double pi = acos(-1.0); 11 typedef long long LL; 12 13 struct Complex { 14 double x,y; 15 Complex() {x=0,y=0;} 16 Complex(double xx,double yy) {x=xx,y=yy;} 17 18 }A[N],B[N]; 19 20 Complex operator + (Complex a,Complex b) { 21 return Complex(a.x+b.x,a.y+b.y); 22 } 23 Complex operator - (Complex a,Complex b) { 24 return Complex(a.x-b.x,a.y-b.y); 25 } 26 Complex operator * (Complex a,Complex b) { 27 return Complex(a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y); 28 } 29 30 void FFT(Complex *a,int n,int ty) { 31 if (n==1) return ; 32 Complex a1[n>>1],a2[n>>1]; 33 for (int i=0; i<=n; i+=2) { 34 a1[i>>1] = a[i],a2[i>>1] = a[i+1]; 35 } 36 FFT(a1,n>>1,ty); 37 FFT(a2,n>>1,ty); 38 Complex w1 = Complex(cos(2.0*pi/n),ty*sin(2.0*pi/n)); 39 Complex w = Complex(1.0,0.0); 40 for (int i=0; i<(n>>1); i++) { 41 Complex t = w * a2[i]; 42 a[i+(n>>1)] = a1[i] - t; 43 a[i] = a1[i] + t; 44 w = w * w1; 45 } 46 } 47 int main() { 48 int n,m; 49 scanf("%d%d",&n,&m); 50 for (int i=0; i<=n; ++i) scanf("%lf",&A[i].x); 51 for (int i=0; i<=m; ++i) scanf("%lf",&B[i].x); 52 int fn = 1; 53 while (fn <= n+m) fn <<= 1; 54 FFT(A,fn,1); 55 FFT(B,fn,1); 56 for (int i=0; i<=fn; ++i) 57 A[i] = A[i] * B[i]; 58 FFT(A,fn,-1); 59 for (int i=0; i<=n+m; ++i) 60 printf("%d ",(int)(A[i].x/fn+0.5)); 61 return 0; 62 }
非递归
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 7 using namespace std; 8 const int N = 300100; 9 const double eps = 1e-8; 10 const double pi = acos(-1.0); 11 typedef long long LL; 12 13 struct Complex { 14 double x,y; 15 Complex() {x=0,y=0;} 16 Complex(double xx,double yy) {x=xx,y=yy;} 17 18 }A[N],B[N]; 19 20 Complex operator + (Complex a,Complex b) { 21 return Complex(a.x+b.x,a.y+b.y); 22 } 23 Complex operator - (Complex a,Complex b) { 24 return Complex(a.x-b.x,a.y-b.y); 25 } 26 Complex operator * (Complex a,Complex b) { 27 return Complex(a.x*b.x-a.y*b.y,a.x*b.y+b.x*a.y); 28 } 29 void FFT(Complex a[],int n,int ty) { 30 for (int i=0,j=0; i<n; ++i) { 31 if (i < j) swap(a[i],a[j]); 32 for (int k=n>>1; (j^=k)<k; k>>=1);//----- 33 } 34 for (int s=1; (1<<s)<=n; ++s) { 35 int m = (1 << s); 36 Complex w1 = Complex(cos(2*pi/m),ty*sin(2*pi/m)); 37 for (int i=0; i<n; i+=m) { 38 Complex w = Complex(1,0); 39 for (int k=0; k<(m>>1); ++k) { 40 Complex t = w*a[i+k+(m>>1)]; 41 a[i+k+(m>>1)] = a[i+k] - t;//----- 42 a[i+k] = a[i+k] + t; //----- 43 w = w*w1; 44 } 45 } 46 } 47 } 48 int main() { 49 int n,m; 50 scanf("%d%d",&n,&m); 51 for (int i=0; i<=n; ++i) scanf("%lf",&A[i].x); 52 for (int i=0; i<=m; ++i) scanf("%lf",&B[i].x); 53 int fn = 1; 54 while (fn <= n+m) fn <<= 1; 55 FFT(A,fn,1); 56 FFT(B,fn,1); 57 for (int i=0; i<=fn; ++i) 58 A[i] = A[i] * B[i]; 59 FFT(A,fn,-1); 60 for (int i=0; i<=n+m; ++i) 61 printf("%d ",(int)(A[i].x/fn+0.5)); 62 return 0; 63 }
图论
树上倍增lca模板(例题https://www.luogu.org/problem/show?pid=3379)
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 5 using namespace std; 6 const int N = 1000100; 7 8 struct Edge{ 9 int v,nxt; 10 }e[N]; 11 int fa[N][25]; //开25,一开始开的20,找了好长时间的错误 12 int deth[N]; 13 int head[N]; 14 int n,m,s,cnt,a,b,d; 15 16 void add(int u,int v) 17 { 18 cnt++; 19 e[cnt].v = v; 20 e[cnt].nxt = head[u]; 21 // e[cnt]=(Edge) {v,head[u]}; 22 head[u] = cnt; 23 } 24 25 void dfs(int x) 26 { 27 for (int i=head[x]; i; i=e[i].nxt) 28 { 29 int v = e[i].v; 30 if(!deth[v])//判重,因为扫过的点都有了深度,也可以另设一个v数组 31 { 32 deth[v] = deth[x]+1; 33 fa[v][0] = x; 34 dfs(v); 35 } 36 } 37 } 38 39 void init() 40 { 41 for (int j=1; j<=20; ++j) 42 for (int i=1; i<=n; ++i) 43 fa[i][j] = fa[fa[i][j-1]][j-1]; 44 } 45 46 int lca(int u,int v) 47 { 48 if (deth[u] < deth[v]) swap(u,v); 49 /*for (int i=20; i>=0; --i) 50 { 51 if (deth[fa[u][i]] >= deth[v]) 52 u = fa[u][i]; 53 }*/ 54 d = deth[u]-deth[v]; //位运算 55 for (int i=0; i<=20; ++i) 56 { 57 if ((1<<i) & d) 58 u = fa[u][i]; 59 } 60 if (u==v) return u; 61 for (int i=20; i>=0; --i) 62 { 63 if(fa[u][i] != fa[v][i]) 64 { 65 u = fa[u][i]; 66 v = fa[v][i]; 67 } 68 } 69 return fa[u][0]; 70 } 71 72 int main() 73 { 74 scanf("%d%d%d",&n,&m,&s); 75 for (int i=1; i<n; ++i) 76 { 77 scanf("%d%d",&a,&b); 78 add(a,b); 79 add(b,a); 80 } 81 deth[s] = 1; 82 fa[s][0] = 0; 83 dfs(s); 84 init(); 85 for (int i=1; i<=m; ++i) 86 { 87 scanf("%d%d",&a,&b); 88 printf("%d ",lca(a,b)); 89 } 90 return 0; 91 }
求树的直径
1 /* 2 我们在树上任选一个节点u,以这个点为根进行一遍dfs,可以求出距离点u最远的点s, 3 再由s为根进行一遍dfs,找到距离s最远的点t,点s与点t之间的路径即为树的直径。 4 */ 5 6 #include<cstdio> 7 #include<cstring> 8 #include<vector> 9 #include<algorithm> 10 using namespace std; 11 const int MAXN = 100010; 12 int dis[MAXN]; 13 vector<int>tree[MAXN]; 14 15 void dfs(int now) 16 { 17 for (int i=0; i<tree[now].size(); ++i) 18 { 19 if (!dis[tree[now][i]]) 20 { 21 dis[tree[now][i]] = dis[now]+1; 22 dfs(tree[now][i]); 23 } 24 } 25 } 26 27 int main() 28 { 29 int n,t,ans; 30 scanf("%d",&n); 31 for (int u,v,i=1; i<n; ++i) 32 { 33 scanf("%d%d",&u,&v); 34 tree[u].push_back(v); 35 tree[v].push_back(u); 36 } 37 t = 1; 38 dis[t] = 0; 39 dfs(t); 40 for (int i=1; i<=n; ++i) 41 if (dis[i]>dis[t]) t = i; 42 memset(dis,0,sizeof(dis)); 43 dis[t] = 0; 44 dfs(t); 45 ans = 1; 46 for (int i=1; i<n; ++i) 47 if (dis[i]>dis[ans]) ans = i; 48 printf("%d",dis[ans]); 49 return 0; 50 }
最小生成树 kruskal 算法(例题https://www.luogu.org/problem/show?pid=3366)
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 5 using namespace std; 6 7 struct edge{ 8 int a,b,c; 9 }e[200100]; 10 int n,m; 11 int far[5100]; 12 int ans,cnt; 13 14 int find(int a) 15 { 16 return far[a]==a?a:far[a]=find(far[a]); 17 } 18 bool cmp(edge a,edge b) 19 { 20 return a.c<b.c; 21 } 22 23 int main() 24 { 25 scanf("%d%d",&n,&m); 26 for(int i=1;i<=n;++i) far[i] = i; 27 for(int i=1;i<=m;++i) 28 { 29 int a,b,c; 30 scanf("%d%d%d",&a,&b,&c); 31 e[i].a=a; 32 e[i].b=b; 33 e[i].c=c; 34 } 35 sort(e+1,e+m+1,cmp); 36 for(int i=1;i<=m;++i) 37 { 38 int aa = find(e[i].a); 39 int bb = find(e[i].b); 40 if(aa!=bb) 41 { 42 cnt++; 43 far[aa] = bb; 44 ans += e[i].c; 45 if(cnt==(n-1))break; 46 } 47 } 48 if(cnt==(n-1)) cout<<ans; 49 else cout<<"orz"; 50 return 0; 51 }
最短路 spfa 算法 (例题https://www.luogu.org/problem/show?pid=3371)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<queue> 5 using namespace std; 6 const int MAXN = 10100; 7 8 struct Edge{ 9 int to,w,nxt; 10 }e[500100]; 11 12 int dis[MAXN]; 13 int head[MAXN]; 14 bool vis[MAXN]; 15 queue<int>q; 16 int n,m,s,cnt; 17 18 void add(int u,int v,int w) //从u到v有一条长度是w的边 19 { 20 ++cnt; 21 e[cnt].to = v; 22 e[cnt].w = w; 23 e[cnt].nxt = head[u]; 24 head[u] = cnt; 25 } 26 27 void spfa() 28 { 29 for (int i=1; i<=n; ++i) 30 dis[i] = 2147483647; 31 dis[s] = 0; 32 q.push(s); 33 vis[s] = true; 34 while (!q.empty()) 35 { 36 int u = q.front(); 37 q.pop(); 38 for (int i=head[u]; i; i=e[i].nxt) 39 { 40 int v = e[i].to; 41 int w = e[i].w; 42 if (dis[v]>dis[u]+w) 43 { 44 dis[v] = dis[u]+w; 45 if (!vis[v]) 46 { 47 q.push(v); 48 vis[v] = true; 49 } 50 } 51 } 52 vis[u] = false; 53 } 54 } 55 56 int main() 57 { 58 scanf("%d%d%d",&n,&m,&s); 59 for (int u,v,w,i=1; i<=m; ++i) 60 { 61 scanf("%d%d%d",&u,&v,&w); 62 add(u,v,w); //有向图,如果是无向图加一行add(v,u,w); 63 } 64 spfa(); 65 for (int i=1; i<=n; ++i) 66 printf("%d ",dis[i]); 67 return 0; 68 }
最短路 dijkstra 算法
1 const int MAXN = 1010; 2 int dis[MAXN]; 3 int pre[MAXN]; 4 int w[MAXN][MAXN]; 5 bool vis[MAXN]; // 判断是否已存入该点松弛过 6 int n; //点 7 8 void Dijkstra(int st) 9 { 10 for (int i=1; i<=n; ++i) dis[i] = w[st][i]; 11 dis[st] = 0; 12 vis[st] = true; 13 pre[st] = 0; 14 for (int i=1; i<=n-1; i++) 15 { 16 int minn = 1e8; 17 int u = 0; // 找出当前未使用的点j的dist[j]最小值 18 for (int j=1; j<=n; ++j) 19 if (!vis[j] && dis[j]<minn) 20 { 21 u = j; // u保存当前邻接点中距离最小的点的号码 22 minn = dis[j]; 23 } 24 if (u==0) break; 25 vis[u] = true; 26 for(int v=1; v<=n; v++) 27 if(dis[u] + w[u][v] < dis[v]) //在通过新加入的u点路径找到离v0点更短的路径 28 { 29 dis[v] = dis[u]+w[u][v]; //更新dist 30 pre[v] = u; //记录前驱顶点 31 } 32 } 33 }
堆优化的dijkstra
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 5 using namespace std; 6 7 const int N = 10100; 8 const int M = 500100; 9 10 struct Edge{ 11 int to,nxt,w; 12 }e[M]; 13 struct Node{ 14 int x,dis; 15 bool operator < (const Node &a) const { 16 return dis > a.dis; 17 } 18 Node() {} 19 Node(int a,int b) {x = a,dis = b;} 20 }now; 21 int head[N],tot,dis[N]; 22 bool vis[N]; 23 priority_queue<Node>q; 24 int n,m,s; 25 26 inline int read() { 27 int x = 0,f = 1;char ch = getchar(); 28 for (; ch<'0'||ch>'9'; ch = getchar()) 29 if (ch=='-') f = -1; 30 for (; ch>='0'&&ch<='9'; ch = getchar()) 31 x = x*10+ch-'0'; 32 return x*f; 33 } 34 inline void add_edge(int u,int v,int w) { 35 e[++tot].to = v,e[tot].w = w,e[tot].nxt = head[u],head[u] = tot; 36 // e[++tot].to = u,e[tot].w = w,e[tot].nxt = head[v],head[v] = tot; 37 } 38 void Dijkstra() { 39 for (int i=1; i<=n; ++i) dis[i] = 2147483647; 40 memset(vis,false,sizeof(vis)); 41 dis[s] = 0; 42 q.push(Node(s,0)); 43 while (!q.empty()) { 44 now = q.top(); 45 q.pop(); 46 int u = now.x; 47 if (vis[u]) continue; 48 vis[u] = true; 49 for (int i=head[u]; i; i=e[i].nxt) { 50 int v = e[i].to,w = e[i].w; 51 if (dis[v] > dis[u]+w) { 52 dis[v] = dis[u]+w; 53 q.push(Node(v,dis[v])); 54 } 55 } 56 57 } 58 } 59 int main() { 60 n = read(),m = read(),s = read(); 61 for (int i=1; i<=m; ++i) { 62 int u = read(),v = read(),w = read(); 63 add_edge(u,v,w); 64 } 65 Dijkstra(); 66 for (int i=1; i<=n; ++i) printf("%d ",dis[i]); 67 return 0; 68 }
网络流dinic算法
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 using namespace std; 6 7 const int MAXN = 100100; 8 const int INF = 1e9; 9 10 struct Edge{ 11 int to,c,nxt; 12 Edge(){} 13 Edge(int tt,int cc,int nn) {to = tt,c = cc,nxt = nn;} 14 }e[1000100]; 15 queue<int>q; 16 17 int head[MAXN],dis[MAXN]; 18 int s,t,n,m,tot = 1; 19 20 int read() 21 { 22 int x = 0, f = 1;char ch = getchar(); 23 while (ch<'0'||ch>'9') {if (ch=='-') f = -1; ch = getchar();} 24 while (ch>='0'&&ch<='9') {x = x*10+ch-'0'; ch = getchar();} 25 return x*f; 26 } 27 bool bfs() 28 { 29 q.push(s); 30 memset(dis,-1,sizeof(dis)); 31 dis[s] = 0; 32 while (!q.empty()) 33 { 34 int u = q.front(); 35 q.pop(); 36 for (int i=head[u]; i; i=e[i].nxt) 37 { 38 int v = e[i].to; 39 if (dis[v]==-1&&e[i].c>0) 40 { 41 dis[v] = dis[u]+1; 42 q.push(v); 43 } 44 } 45 } 46 if (dis[t]!=-1) return true; 47 return false; 48 } 49 int dfs(int u,int low) 50 { 51 if (u==t) return low; 52 int w,used = 0; 53 for (int i=head[u]; i; i=e[i].nxt) 54 { 55 int v = e[i].to; 56 if (dis[v]==dis[u]+1&&e[i].c>0) 57 { 58 w = dfs(v,min(low-used,e[i].c)); 59 e[i].c -= w; 60 e[i^1].c += w; 61 used += w; 62 if (used==low) return low; 63 } 64 } 65 if (!used) dis[u] = -1; 66 return used; 67 } 68 int dinic() 69 { 70 int ans = 0,t; 71 while (bfs()) 72 ans += dfs(s,INF); 73 return ans; 74 } 75 int main() 76 { 77 n = read();m = read();s = read();t = read(); 78 for (int u,v,w,i=1; i<=m; ++i) 79 { 80 u = read();v = read();w = read(); 81 e[++tot] = Edge(v,w,head[u]); 82 head[u] = tot; 83 e[++tot] = Edge(u,0,head[v]); 84 head[v] = tot; 85 } 86 printf("%d",dinic()); 87 return 0; 88 }
KM算法 HDU2255
1 #include<cstdio> 2 #include<cctype> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long LL; 7 8 inline int read() { 9 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 10 for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 11 } 12 13 const int INF = 1e9; 14 const int N = 305; //-- 15 int match[N], mp[N][N], lx[N], ly[N], slack[N]; 16 bool visx[N], visy[N]; 17 int n; 18 19 bool dfs(int u) { 20 visx[u] = true; 21 for (int v=1; v<=n; ++v) { 22 if (visy[v]) continue; 23 int t = lx[u] + ly[v] - mp[u][v]; 24 if (!t) { 25 visy[v] = true; 26 if (!match[v] || dfs(match[v])) { 27 match[v] = u; 28 return true; 29 } 30 } 31 else slack[v] = min(slack[v], t); 32 } 33 return false; 34 } 35 void KM() { 36 memset(match, 0, sizeof(match)); 37 memset(ly, 0, sizeof(ly)); 38 for (int i=1; i<=n; ++i) 39 for (int j=1; j<=n; ++j) 40 lx[i] = max(lx[i], mp[i][j]); 41 42 for (int x=1; x<=n; ++x) { 43 for (int i=1; i<=n; ++i) slack[i] = INF; 44 while (true) { 45 memset(visx, false, sizeof(visx)); 46 memset(visy, false, sizeof(visy)); 47 if (dfs(x)) break; 48 int d = INF; 49 for (int i=1; i<=n; ++i) 50 if (!visy[i]) d = min(d, slack[i]); 51 for (int i=1; i<=n; ++i) { 52 if (visx[i]) lx[i] -= d; 53 if (visy[i]) ly[i] += d; 54 else slack[i] -= d; 55 } 56 } 57 } 58 } 59 int main() { 60 while (~scanf("%d",&n)) { 61 for (int i=1; i<=n; ++i) 62 for (int j=1; j<=n; ++j) mp[i][j] = read(); 63 KM(); 64 int ans = 0; 65 for (int i=1; i<=n; ++i) 66 if (match[i]) ans += mp[match[i]][i]; 67 printf("%d ",ans); 68 } 69 return 0; 70 }
数据结构
树状数组,单点查询,区间修改(例题https://www.luogu.org/problem/show?pid=3368)需要用到差分的思想,即数列前后两个数的差。数组不需要开四倍
1 //树状数组:区间修改,单点查询,差分 2 #include<cstdio> 3 int sum[500100]; 4 int n,m,last = 0; 5 int lowbit(int x) 6 { 7 return x&(-x); 8 } 9 void update(int x,int v) 10 { 11 while (x<=n) 12 { 13 sum[x] += v; 14 x += lowbit(x); 15 } 16 } 17 int query(int x) 18 { 19 int ans = 0; 20 while (x) 21 { 22 ans += sum[x]; 23 x -= lowbit(x); 24 } 25 return ans; 26 } 27 int main() 28 { 29 scanf("%d%d",&n,&m); 30 for (int a,i=1; i<=n; ++i) 31 { 32 scanf("%d",&a); 33 update(i,a-last); 34 last = a; 35 } 36 for (int x,y,z,a,i=1; i<=m; ++i) 37 { 38 scanf("%d",&a); 39 if (a==1) //区间修改 40 { 41 scanf("%d%d%d",&x,&y,&z); 42 update(x,z); 43 update(y+1,-z); 44 } 45 else //单点查询 46 { 47 scanf("%d",&x); 48 printf("%d ",query(x)); 49 } 50 } 51 return 0; 52 }
树状数组,单点修改,区间查询(例题https://www.luogu.org/problem/show?pid=3374)这个不需要用差分
1 //树状数组:区间查询,单点修改 2 #include<cstdio> 3 int sum[500100]; 4 int n,m; 5 int lowbit(int x) 6 { 7 return x&(-x); 8 } 9 void update(int x,int v) 10 { 11 while (x<=n) 12 { 13 sum[x] += v; 14 x += lowbit(x); 15 } 16 } 17 int query(int x) 18 { 19 int ans = 0; 20 while (x) 21 { 22 ans += sum[x]; 23 x -= lowbit(x); 24 } 25 return ans; 26 } 27 int main() 28 { 29 scanf("%d%d",&n,&m); 30 for (int a,i=1; i<=n; ++i) 31 { 32 scanf("%d",&a); 33 update(i,a); 34 } 35 for (int i=1; i<=m; ++i) 36 { 37 int x,y,z; 38 scanf("%d%d%d",&z,&x,&y); 39 if (z==1) update(x,y); //单点修改 40 else printf("%d ",query(y)-query(x-1)); 41 } 42 return 0; 43 }
树状数组,区间修改,区间查询 (http://codevs.cn/problem/1082/)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline int read() { 6 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 7 for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 8 } 9 10 const int N = 200010; 11 int a[N],b[N]; 12 13 struct BIT{ 14 int n;LL c1[N],c2[N]; 15 void update(int p,int v) { 16 for (int i=p; i<=n; i+=(i&(-i))) c1[i] += v,c2[i] += p*v; 17 } 18 LL query(int p) { 19 LL ans = 0; 20 for (int i=p; i; i-=(i&(-i))) ans += (p+1)*c1[i]-c2[i]; 21 return ans; 22 } 23 }bit; 24 25 int main() { 26 int n = read(),last = 0; 27 bit.n = n; 28 for (int i=1; i<=n; ++i) { 29 int tmp = read(); 30 a[i] = tmp - last; 31 last = tmp; 32 } 33 for (int i=1; i<=n; ++i) 34 bit.update(i,a[i]); 35 36 int m = read(); 37 while (m--) { 38 int opt = read(); 39 if (opt == 1) { 40 int l = read(),r = read(),v = read(); 41 bit.update(l,v); 42 if (r < n) bit.update(r+1,-v); 43 } 44 else { 45 int l = read(),r = read(); 46 printf("%lld ",bit.query(r)-bit.query(l-1)); 47 } 48 } 49 return 0; 50 }
树链剖分
1 void dfs1(int u,int f,int d) //找重孩子 ,u是当前节点,f节点的父亲,d深度 2 { 3 dep[u] = d; 4 fa[u] = f; 5 siz[u] = 1; 6 for (int i=head[u]; i; i=e[i].nxt) 7 { 8 int v = e[i].to; 9 if (v!=f) 10 { 11 dfs1(v,u,d+1); 12 siz[u] += siz[v]; 13 if (siz[v]>siz[son[u]])//son[]数组,用来保存重儿子 14 son[u] = v; 15 } 16 } 17 } 18 void dfs2(int x) //找重链 19 { 20 int t = 0; 21 if (!top[x]) top[x] = x; 22 for (int i=head[x]; i; i=e[i].nxt) 23 if (fa[x]!=e[i].to&&siz[t]<siz[e[i].to]) 24 t = e[i].to; 25 if (t) top[t] = top[x], dfs2(t); 26 for (int i=head[x]; i; i=e[i].nxt) 27 if(fa[x]!=e[i].to&&t!=e[i].to) dfs2(e[i].to); 28 } 29 30 /* 31 siz[]数组,用来保存以x为根的子树节点个数 32 top[]数组,用来保存当前节点的所在链的顶端节点 33 son[]数组,用来保存重儿子 34 dep[]数组,用来保存当前节点的深度 35 fa[]数组,用来保存当前节点的父亲 36 */
splay 基本的插入,删除,查询x数的排名,查询排名为x的数,求x的前驱,后继(例题http://www.lydsy.com/JudgeOnline/problem.php?id=3224)
1 #include<cstdio> 2 3 const int N = 100010; 4 int fa[N],ch[N][2],siz[N],cnt[N],data[N]; 5 int tn,Root; 6 7 inline char nc() { 8 static char buf[100000],*p1 = buf,*p2 = buf; 9 return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2) ? EOF :*p1++; 10 } 11 inline int read() { 12 int x = 0,f = 1;char ch=nc(); 13 for (; ch<'0'||ch>'9'; ch = nc()) 14 if (ch == '-') f = -1; 15 for (; ch>='0'&&ch<='9'; ch = nc()) 16 x = x*10+ch-'0'; 17 return x * f; 18 } 19 inline int son(int x) { 20 return x == ch[fa[x]][1]; // - 21 } 22 inline void pushup(int x) { 23 siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + cnt[x]; 24 } 25 inline void rotate(int x) { 26 int y = fa[x],z = fa[y],b = son(x),c = son(y),a = ch[x][!b]; 27 if (z) ch[z][c] = x;else Root = x;fa[x] = z; // 调整x的位置 28 ch[x][!b] = y;fa[y] = x; // 调整y的位置 29 ch[y][b] = a;if (a) fa[a] = y; // 给y另一个子节点 30 pushup(y);pushup(x); 31 } 32 inline void splay(int x,int rt) { 33 while (fa[x] != rt) { 34 int y = fa[x],z = fa[y]; 35 if (z==rt) rotate(x); 36 else { 37 if (son(x)==son(y)) rotate(y),rotate(x); 38 else rotate(x),rotate(x); 39 } 40 } 41 } 42 inline int getpre(int x) { //得到第一个比x小的数 43 int p = Root,ans; 44 while (p) { 45 if (x <= data[p]) p = ch[p][0]; 46 else ans = p,p = ch[p][1]; 47 } 48 return ans; 49 } 50 inline int getsuc(int x) { // 得到第一个比x大的数 51 int p = Root,ans; 52 while (p) { 53 if (x >= data[p]) p = ch[p][1]; 54 else ans = p,p = ch[p][0]; 55 } 56 return ans; 57 } 58 inline int getk(int k) { // 得到k的排名 59 int p = Root,ans = 0; 60 while (true) { 61 if (k < data[p]) p = ch[p][0]; 62 else { 63 ans += (ch[p][0] ? siz[ch[p][0]] : 0); 64 if (k==data[p]) { 65 splay(p,0);return ans+1; 66 } 67 ans += cnt[p]; 68 p = ch[p][1]; 69 } 70 } 71 } 72 inline int getkth(int k) { // 得到第k个数 73 int p = Root; 74 while (true) { 75 if (ch[p][0] && k <= siz[ch[p][0]]) p = ch[p][0]; 76 else { 77 int tmp = (ch[p][0] ? siz[ch[p][0]] : 0) + cnt[p]; 78 if (k <= tmp) return data[p]; 79 k -= tmp; p = ch[p][1]; 80 } 81 } 82 } 83 inline void Insert(int x) { // 插入 84 if (Root==0) { 85 ++tn; Root = tn; 86 ch[tn][1] = ch[tn][0] = fa[tn] = 0; 87 siz[tn] = cnt[tn] = 1;data[tn] = x; 88 return; 89 } 90 int p = Root,pa = 0; 91 while (true) { 92 if (x==data[p]) { 93 cnt[p]++;pushup(p);pushup(pa);splay(p,0);break; 94 } 95 pa = p; 96 p = ch[p][x > data[p]]; 97 if (p==0) { 98 tn++; 99 ch[tn][1] = ch[tn][0] = 0;siz[tn] = cnt[tn] = 1; 100 fa[tn] = pa;ch[pa][x > data[pa]] = tn;data[tn] = x; //- 101 pushup(pa),splay(tn,0);break; 102 } 103 } 104 } 105 inline void Clear(int x) { 106 ch[x][0] = ch[x][1] = fa[x] = siz[x] = cnt[x] = data[x] = 0; 107 } 108 inline void Delete(int x) { // 删除 109 getk(x); 110 if (cnt[Root] > 1) {cnt[Root]--;pushup(Root);return;} 111 if (!ch[Root][0] && !ch[Root][1]) {Clear(Root);Root = 0;return;} 112 if (!ch[Root][0]) { 113 int tmp = Root;Root = ch[Root][1];fa[Root] = 0;Clear(tmp);return; 114 } 115 else if (!ch[Root][1]) { 116 int tmp = Root;Root = ch[Root][0];fa[Root] = 0;Clear(tmp);return; 117 } 118 int tmp = Root,pre = ch[Root][0];//可以是getpre(data[Root]);等价于下面的while 119 while (ch[pre][1]) pre = ch[pre][1]; 120 splay(pre,0); 121 ch[Root][1] = ch[tmp][1]; 122 fa[ch[tmp][1]] = Root; 123 Clear(tmp); 124 pushup(Root); 125 } 126 int main() { 127 int n = read(); 128 while (n--){ 129 int opt = read(),x = read(); 130 if (opt==1) Insert(x); 131 else if (opt==2) Delete(x); 132 else if (opt==3) printf("%d ",getk(x)); 133 else if (opt==4) printf("%d ",getkth(x)); 134 else if (opt==5) printf("%d ",data[getpre(x)]); 135 else printf("%d ",data[getsuc(x)]); 136 } 137 return 0; 138 }
虚树的建立
1 bool cmp_dfn(int a,int b) { 2 return dfn[a] < dfn[b]; 3 } 4 void Insert(int p) { 5 int x = sk[top], lca = LCA(x, p); 6 if (lca == x) { sk[++top] = p; return ; } 7 while (lca != x) { 8 int y = sk[--top]; 9 if (dfn[y] < dfn[lca]) { 10 add_edge(lca, x); sk[++top] = lca; 11 break; 12 } 13 add_edge(y, x); x = y; 14 } 15 sk[++top] = p; 16 } 17 void build() { 18 int k = read(); 19 for (int i=1; i<=k; ++i) A[i] = read(); 20 sort(A + 1, A + k + 1, cmp_dfn); 21 top = 0; sk[++top] = 1; 22 if (A[1] != 1) sk[++top] = A[1]; 23 else sk[++top] = A[2]; 24 for (int i=(A[1]!=1?2:3); i<=k; ++i) Insert(A[i]); 25 while (--top) add_edge(sk[top], sk[top + 1]); 26 }
字符串
kmp模板(例题https://www.luogu.org/problem/show?pid=3375)
1 #include<cstdio> 2 #include<cstring> 3 4 char a[1000100],b[1010]; 5 int p[1010]; //最长公共前后缀长度 6 int s1,s2; 7 void init() 8 { 9 int j = 0; 10 p[0] = 0; 11 for (int i=1; i<s2; ++i) 12 { 13 while(j>0 && b[i]!=b[j]) j = p[j-1]; 14 if(b[i]==b[j]) j++; 15 p[i] = j; 16 } 17 } 18 void kmp() 19 { 20 int j = 0; 21 for (int i=0; i<s1; ++i) 22 { 23 while(j>0 && a[i]!=b[j]) j = p[j-1]; 24 if(a[i]==b[j]) j++; 25 if(j==s2) printf("%d ",i+1-s2+1); //找到匹配输出i的值,第一个字符是 0,所以加1 26 } 27 } 28 int main() 29 { 30 scanf("%s",a); 31 scanf("%s",b); 32 s1 = strlen(a); 33 s2 = strlen(b); 34 init(); 35 kmp(); 36 for(int i=0;i<s2;++i) 37 printf("%d ",p[i]); 38 return 0; 39 }
manacher算法,求最长回文串(例题https://www.luogu.org/problem/show?pid=3805)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #define MAXN 31000000 5 using namespace std; 6 7 char s[MAXN],str[MAXN]; 8 int p[MAXN],len; 9 10 void init() 11 { 12 len = strlen(str); 13 s[0] = '#'; 14 for (int i=0; i<len; ++i) 15 { 16 s[i<<1|1] = '#'; 17 s[(i+1)<<1] = str[i]; 18 } 19 s[len<<1|1] = '#'; 20 len = (len<<1|1); 21 } 22 int manacher() 23 { 24 int mx = 0, id; 25 for (int i=1; i<=len; ++i) 26 { 27 if (mx>i) p[i] = min(p[id<<1-1],mx-i); 28 else p[i] = 1; 29 while (s[i+p[i]]==s[i-p[i]]) p[i]++; 30 if (p[i]+i>mx) 31 mx = p[i]+i, id = i; 32 } 33 int ans = 0; 34 for (int i=1; i<len; ++i) ans = max(ans,p[i]); 35 return ans-1; 36 } 37 int main() 38 { 39 scanf("%s",str); 40 init(); 41 printf("%d",manacher()); 42 return 0; 43 }
trie树,结构体封装函数
1 struct Trie 2 { 3 int ch[MAXN][26];//MAXN=字符集*长度 4 int val[MAXN]; 5 int size; 6 Trie() //或者:函数Clear() 7 { 8 size = 1; 9 memset(ch,0,sizeof(ch)); 10 memset(val,0,sizeof(val)); 11 } 12 int id(char c) 13 { 14 return c-'a'; 15 } 16 void Insert(char* s) 17 { 18 int u = 0, len = strlen(s); 19 for (int i=0; i<len; ++i) 20 { 21 int c = id(s[i]); 22 if (!ch[u][c]) ch[u][c] = size++; 23 u = ch[u][c]; 24 //如果是统计前缀单词个数,在此处上val[u]++;下面的val[u]=1删掉 25 } 26 val[u] = 1;//标记单词是否出现过 27 } 28 bool Find(char* s) 29 { 30 int u = 0, len = strlen(s); 31 for (int i=0; i<len; ++i) 32 { 33 int c = id(s[i]); 34 if (!ch[u][c]) return false; 35 u = ch[u][c]; 36 } 37 if (val[u]) return true;//统计前缀单词个数,return val[u]; 38 return false; 39 } 40 }t;
AC自动机模板
1 //AC自动机 2 struct AC_automaton{ 3 int ch[MAXN][26],val[MAXN],last[MAXN],fail[MAXN],size,ret; 4 void clear() 5 { 6 memset(ch[0],0,sizeof(ch[0])); 7 memset(val,0,sizeof(val)); 8 memset(fail,0,sizeof(fail)); 9 size = 0; 10 ret = 0; 11 } 12 int idx(char c) 13 { 14 return c-'a'; 15 } 16 void insert(char *s)//插入一个字符串 17 { 18 int u = 0,len = strlen(s); 19 for (int i=0; i<len; ++i) 20 { 21 int c = idx(s[i]); 22 if (!ch[u][c]) 23 { 24 ch[u][c] = ++size; 25 val[size] = 0; 26 memset(ch[size],0,sizeof(ch[size])); 27 } 28 u = ch[u][c]; 29 } 30 val[u] ++; 31 } 32 void getfail()//处理fail指针 33 { 34 queue<int>q; 35 fail[0] = 0; 36 for (int c=0; c<26; ++c) 37 { 38 int u = ch[0][c]; 39 if (u) 40 { 41 fail[u] = 0;q.push(u);last[u] = 0; 42 } 43 } 44 while (!q.empty()) 45 { 46 int r = q.front();q.pop(); 47 for (int c=0; c<26; ++c) 48 { 49 int u = ch[r][c]; 50 if (!u) 51 { 52 ch[r][c] = ch[fail[r]][c];//有这一行就可以减去89行 53 continue; 54 } 55 q.push(u); 56 int v = fail[r]; 57 while (v && !ch[v][c]) v = fail[v]; 58 fail[u] = ch[v][c]; 59 last[u] = val[fail[u]] ? fail[u] : last[fail[u]]; 60 } 61 } 62 } 63 void solve(int j)//可以任意改变的函数,看题目需要什么,这个是处理文本串中有多少个模式串 64 { 65 if (!j) return ; 66 if (val[j]) 67 { 68 ret += val[j]; 69 val[j] = 0; 70 } 71 solve(last[j]); 72 } 73 void find(char *T)//遍历一遍文本串 74 { 75 int j = 0,len = strlen(T); 76 for (int i=0; i<len; ++i) 77 { 78 int c = idx(T[i]); 79 //while (j && !ch[j][c]) j = fail[j]; 80 j = ch[j][c]; 81 if (val[j]) solve(j); 82 else if (last[j]) solve(last[j]); 83 } 84 } 85 86 }ac;
后缀数组
1 int s[N]; 2 int t1[N],t2[N],c[N],sa[N],height[N],rank[N]; 3 int n,m = 130,k; 4 5 void get_sa() { 6 int i,p,*x = t1,*y = t2; 7 for (i=0; i<m; ++i) c[i] = 0; 8 for (i=0; i<n; ++i) x[i] = s[i],c[x[i]]++; 9 for (i=1; i<m; ++i) c[i] += c[i-1]; 10 for (i=n-1; i>=0; --i) sa[--c[x[i]]] = i; 11 for (int k=1; k<=n; k<<=1) { 12 p = 0; 13 for (i=n-k; i<n; ++i) y[p++] = i; 14 for (i=0; i<n; ++i) if(sa[i]>=k) y[p++]=sa[i]-k; 15 for (i=0; i<m; ++i) c[i] = 0; 16 for (i=0; i<n; ++i) c[ x[y[i]] ]++; 17 for (i=1; i<m; ++i) c[i] += c[i-1]; 18 for (i=n-1; i>=0; --i) sa[--c[ x[y[i]] ]] = y[i]; 19 swap(x,y); 20 p = 1; 21 x[sa[0]] = 0; 22 for (i=1; i<n; ++i) 23 x[sa[i]] = y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k] ? p-1:p++; 24 if (p>=n) break; 25 m = p; 26 } 27 } 28 void get_height() { 29 for (int i=0; i<n; ++i) rank[sa[i]] = i; 30 int k = 0; 31 height[0] = 0; 32 for (int i=0; i<n; ++i) { 33 if (!rank[i]) continue; 34 if (k) k--; 35 int j = sa[rank[i]-1]; 36 while (i+k<n && j+k<n && s[i+k]==s[j+k]) k++; 37 height[rank[i]] = k; 38 } 39 }
Hash
1 void init() { 2 mi[0] = 1; 3 for (int i=1; i<=n; ++i) mi[i] = mi[i - 1] * Base; 4 for (int i=1; i<=n; ++i) Hash[i] = Hash[i - 1] * Base + (s[i] - 'a' + 1); 5 } 6 uLL gethash(int l,int r) { 7 return Hash[r] - Hash[l] * mi[r - l + 1]; 8 }
计算几何
Graham求凸包,luogu2742
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cctype> 6 #include<cmath> 7 using namespace std; 8 typedef long long LL; 9 10 double read() { 11 double x = 0, f = 1, y = 0.1; char ch = getchar(); 12 for (; !isdigit(ch)&&ch!='.'; ch=getchar()) if (ch=='-') f = -1; 13 for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; 14 if (ch == '.') ch = getchar(); 15 for (; isdigit(ch); ch=getchar()) x += (ch - '0') * y, y *= 0.1; 16 return x * f; 17 } 18 19 const double eps = 1e-8; 20 21 struct Vector{ 22 double x,y; 23 Vector() {} 24 Vector(double a,double b) { x = a, y = b; } 25 }; 26 typedef Vector Point; 27 Vector operator + (Vector a,Vector b) { return Vector(a.x+b.x, a.y+b.y); } 28 Vector operator - (Vector a,Vector b) { return Vector(a.x-b.x, a.y-b.y); } 29 Vector operator * (Vector a,double p) { return Vector(a.x * p, a.y * p); } 30 Vector operator / (Vector a,double p) { return Vector(a.x / p, a.y / p); } 31 bool operator == (Point a,Point b) { return (a.x == b.x) && (a.y == b.y); } 32 33 int dcmp(double x) { 34 if (fabs(x) <= eps) return 0; 35 return x > 0 ? x : -x; 36 } 37 double cross(Vector a, Vector b) { 38 return a.x * b.y - a.y * b.x; 39 } 40 double len(Vector a) { 41 return sqrt(a.x * a.x + a.y * a.y); 42 } 43 44 double X,Y; 45 bool cmp_angle(Point a,Point b) { 46 if (atan2(a.y-Y,a.x-X) == atan2(b.y-Y,b.x-X)) return a.x < b.x; 47 return atan2(a.y-Y,a.x-X) < atan2(b.y-Y,b.x-X); 48 } 49 50 const int N = 100100; 51 Point A[N], sk[N]; 52 int n; 53 54 void Graham() { 55 Y = 1e9; 56 int t, Top = 0; 57 for (int i=1; i<=n; ++i) 58 if (A[i].y < Y) Y = A[i].y, X = A[i].x, t = i; 59 swap(A[t],A[1]); 60 sort(A+2,A+n+1,cmp_angle); 61 sk[++Top] = A[1]; 62 sk[++Top] = A[2]; 63 for (int i=3; i<=n; ++i) { 64 // 直线Top-1 -> A[i] 如果在Top-1 -> Top的 外侧,即逆时针旋转过去的,那么Top可以弹出。 65 while (Top > 1 && cross(sk[Top]-sk[Top-1],A[i]-sk[Top-1]) < 0) Top--; 66 sk[++Top] = A[i]; 67 } 68 double ans = 0; 69 for (int i=2; i<=Top; ++i) 70 ans += len(sk[i] - sk[i-1]); 71 ans += len(sk[1] - sk[Top]); 72 printf("%.2lf",ans); 73 } 74 75 int main() { 76 cin >> n; 77 for (int i=1; i<=n; ++i) 78 A[i].x = read(), A[i].y = read(); 79 Graham(); 80 return 0; 81 }
增量排序法求半平面交,poj2451
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cctype> 6 #include<cmath> 7 using namespace std; 8 typedef long long LL; 9 10 double read() { 11 double x = 0, f = 1, y = 0.1; char ch = getchar(); 12 for (; !isdigit(ch)&&ch!='.'; ch=getchar()) if (ch=='-') f = -1; 13 for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; 14 if (ch == '.') ch = getchar(); 15 for (; isdigit(ch); ch=getchar()) x += (ch - '0') * y, y *= 0.1; 16 return x * f; 17 } 18 19 const double eps = 1e-8; 20 21 struct Vector{ 22 double x,y; 23 Vector() {} 24 Vector(double a,double b) { x = a, y = b; } 25 }; 26 typedef Vector Point; 27 Vector operator + (Vector a,Vector b) { return Vector(a.x+b.x, a.y+b.y); } 28 Vector operator - (Vector a,Vector b) { return Vector(a.x-b.x, a.y-b.y); } 29 Vector operator * (Vector a,double p) { return Vector(a.x * p, a.y * p); } 30 Vector operator / (Vector a,double p) { return Vector(a.x / p, a.y / p); } 31 bool operator == (Point a,Point b) { return (a.x == b.x) && (a.y == b.y); } 32 33 struct Line{ 34 Point s, t; 35 double angle; 36 Line () {} 37 Line (Point a,Point b) {s = a, t = b, angle = atan2(b.y - a.y, b.x - a.x);} 38 39 }; 40 41 int dcmp(double x) { 42 if (fabs(x) <= eps) return 0; 43 return x > 0 ? 1 : -1; 44 } 45 double cross(Vector a, Vector b) { 46 return a.x * b.y - a.y * b.x; 47 } 48 Point jiaodian(Line a, Line b) { 49 Point A = a.s, B = a.t, C = b.s, D = b.t; 50 double t1 = cross(D - A, B - A), t2 = cross(B - A, C - A); 51 double t = t1 / (t1 + t2); 52 return C * t + D * (1 - t); 53 } 54 55 const int N = 20010; 56 57 Point A[N]; 58 Line seg[N]; 59 int q[N]; 60 int n,tot; 61 62 bool cmp_angle(Line A,Line B) { // 按极角排序,小的在前,极角相等的话,左边的在前 63 double d = dcmp(A.angle - B.angle); 64 if (!d) return dcmp(cross(B.s - A.s, B.t - A.s)) > 0; 65 return d < 0; 66 } 67 bool judge(Line C,Line A, Line B) { // 判断AB的交点是否在C的左边 68 Point p = jiaodian(A, B); 69 return dcmp(cross(C.s - p, C.t - p)) < 0; // 在C的右边返回true 70 } 71 72 void solve() { 73 sort(seg+1, seg+n+1, cmp_angle); 74 int j = 1; 75 for (int i=2; i<=n; ++i) // 将极角相同的只保留最左边的 76 if (dcmp(seg[i].angle - seg[j].angle) > 0) seg[++j] = seg[i]; 77 n = j; 78 q[1] = 1, q[2] = 2; 79 int L = 1, R = 2; 80 for (int i=3; i<=n; ++i) { 81 while (L < R && judge(seg[i], seg[q[R]], seg[q[R-1]])) R --; // 栈中最后两个线段的交点在这条的右边 82 while (L < R && judge(seg[i], seg[q[L]], seg[q[L+1]])) L ++; // 由于是凸多边形,新加入的线段可能转回来,把起点挡在右边 83 q[++R] = i; 84 } 85 while (L < R && judge(seg[q[L]], seg[q[R]], seg[q[R-1]])) R --; 86 while (L < R && judge(seg[q[L]], seg[q[L]], seg[q[L+1]])) L ++; 87 q[++R] = q[L]; 88 tot = 0; 89 for (int i=L; i<R; ++i) 90 A[++tot] = jiaodian(seg[q[i]], seg[q[i+1]]); // 求交点 91 } 92 93 double Area() { 94 double ans = 0; 95 for (int i=2; i<tot; ++i) 96 ans += cross(A[i]-A[1],A[i+1]-A[1]); 97 return ans / 2.0; 98 } 99 100 int main() { 101 while (~scanf("%d",&n)) { 102 for (int i=1; i<=n; ++i) { 103 double a1 = read(), b1 = read(), a2 = read(), b2 = read(); 104 seg[i] = Line(Point(a1, b1), Point(a2, b2)); 105 } 106 seg[++n] = Line(Point(0, 0), Point(10000, 0)); 107 seg[++n] = Line(Point(10000, 0), Point(10000, 10000)); 108 seg[++n] = Line(Point(10000, 10000), Point(0, 10000)); 109 seg[++n] = Line(Point(0, 10000), Point(0, 0)); 110 solve(); 111 printf("%.1lf ",Area()); 112 } 113 return 0; 114 }
旋转卡壳,求凸包直径,poj2187
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cctype> 6 #include<cmath> 7 using namespace std; 8 typedef long long LL; 9 10 inline int read() { 11 int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch=getchar()) if (ch=='-') f = -1; 12 for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; return x * f; 13 } 14 15 struct Vector{ 16 int x,y; 17 Vector() {} 18 Vector(int a,int b) { x = a, y = b; } 19 }; 20 typedef Vector Point; 21 Vector operator + (Vector a,Vector b) { return Vector(a.x+b.x, a.y+b.y); } 22 Vector operator - (Vector a,Vector b) { return Vector(a.x-b.x, a.y-b.y); } 23 Vector operator * (Vector a,double p) { return Vector(a.x * p, a.y * p); } 24 Vector operator / (Vector a,double p) { return Vector(a.x / p, a.y / p); } 25 bool operator == (Point a,Point b) { return (a.x == b.x) && (a.y == b.y); } 26 27 int len(Vector a) { 28 return a.x * a.x + a.y * a.y; 29 } 30 int cross(Vector a, Vector b) { 31 return a.x * b.y - a.y * b.x; 32 } 33 34 const int N = 50010; 35 Point A[N], sk[N]; 36 double X,Y; 37 int n, Top; 38 39 bool cmp_angle(Point a,Point b) { // --- 40 int t = cross(a - A[1], b - A[1]); 41 if (t > 0 || (t == 0 && len(a - A[1]) > len(b - A[1]))) return true; 42 return false; 43 } 44 45 void Graham() { 46 int t; Top = 0; Y = 1e9; 47 for (int i=1; i<=n; ++i) 48 if (A[i].y < Y || (A[i].y == Y && A[i].x < X)) Y = A[i].y, X = A[i].x, t = i; 49 swap(A[t], A[1]); 50 sort(A+2, A+n+1, cmp_angle); 51 sk[++Top] = A[1]; 52 sk[++Top] = A[2]; 53 for (int i=3; i<=n; ++i) { 54 while (Top > 1 && cross(sk[Top] - sk[Top-1], A[i] - sk[Top-1]) < 0) Top --; 55 sk[++Top] = A[i]; 56 } 57 } 58 int Area(Point a,Point b,Point c) { 59 return cross(b - a, c - a); 60 } 61 void RC() { 62 sk[++Top] = sk[1]; 63 int p = 2; 64 int ans = len(sk[2] - sk[1]); 65 for (int i=1; i<Top; ++i) { 66 while (Area(sk[i],sk[i+1],sk[p+1]) > Area(sk[i],sk[i+1],sk[p])) p = p % Top + 1; 67 ans = max(ans, max(len(sk[p] - sk[i]), len(sk[p] - sk[i+1]))); 68 } 69 printf("%d ",ans); 70 } 71 int main() { 72 while (~scanf("%d",&n)) { 73 for (int i=1; i<=n; ++i) 74 A[i].x = read(), A[i].y = read(); 75 Graham(); 76 RC(); 77 } 78 return 0; 79 }
其他
二分答案
a最小值最大
1 //最小值最大 2 int l = min_ans, r = max_ans; 3 while (l < r) 4 { 5 int mid = (l+r+1)/2; //+1避免 r==l+1 时mid一直等于l,从而死循环 6 if (ok(mid)) //符合条件返回True 7 l = mid; 8 else 9 r = mid - 1; 10 }
b最大值最小
1 //最大值最小 2 int l = min_ans, r = max_ans; 3 while (l < r) 4 { 5 int mid = (l+r)/2; 6 if (ok(mid)) //符合条件返回True 7 r = mid; 8 else 9 l = mid + 1; 10 }
归并排序模板(例题https://www.luogu.org/problem/show?pid=1177)
1 #include<cstdio> 2 3 int n,ans; 4 int a[500100],b[500100]; //a原数组,b暂存数组 5 6 void merge_sort(int l,int r) //归并 7 { 8 if (l==r) return ; //一个数不用排序 9 int m = (l+r)>>1; 10 merge_sort(l,m); //排序左边 11 merge_sort(m+1,r); //排序右边 12 int i = l, j = m+1, k = l ; //i左边最小的位置,j右边最小的位置 13 while (i<=m && j<=r) 14 if (a[i]<=a[j]) b[k++] = a[i++]; 15 else b[k++] = a[j++]; 16 while (i<=m) b[k++] = a[i++]; //加入左边剩余的数 17 while (j<=r) b[k++] = a[j++]; //加入右边剩余的数 18 for (i=l; i<=r; ++i) a[i] = b[i]; //从暂存数组中赋值 19 } 20 21 int main() 22 { 23 scanf("%d",&n); 24 for (int i=1; i<=n; ++i) 25 scanf("%d",&a[i]); 26 merge_sort(1,n); 27 for (int i=1; i<=n; ++i) 28 printf("%d ",a[i]); 29 return 0; 30 }
归并排序求逆序对(例题https://www.luogu.org/problem/show?pid=1908)
1 #include<cstdio> 2 3 int n,ans; 4 int a[500100],b[500100]; //a原数组,b暂存数组 5 6 void merge_sort(int l,int r) //归并 7 { 8 if (l==r) return ; //一个数不用排序 9 int m = (l+r)>>1; 10 merge_sort(l,m); //排序左边 11 merge_sort(m+1,r); //排序右边 12 int i = l, j = m+1, k = l ; //i左边最小的位置,j右边最小的位置 13 while (i<=m && j<=r) 14 if (a[i]<=a[j]) b[k++] = a[i++]; 15 else ans += m-i+1, b[k++] = a[j++]; //加入右半段时,逆序对数增加 16 while (i<=m) b[k++] = a[i++]; //加入左边剩余的数 17 while (j<=r) b[k++] = a[j++]; //加入右边剩余的数 18 for (i=l; i<=r; ++i) a[i] = b[i]; //从暂存数组中赋值 19 } 20 21 int main() 22 { 23 scanf("%d",&n); 24 for (int i=1; i<=n; ++i) 25 scanf("%d",&a[i]); 26 merge_sort(1,n); 27 printf("%d",ans); 28 return 0; 29 }
树状数组求逆序对
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 8 using namespace std; 9 10 const int N = 100010; 11 12 struct Node{ 13 int val,pos; 14 bool operator < (const Node &a) const { 15 return val > a.val; 16 } 17 }a[N]; 18 int sum[N],n; 19 20 inline int read() { 21 int x = 0,f = 1;char ch=getchar(); 22 for (; !isdigit(ch); ch=getchar()) if(ch=='-')f=-1; 23 for (; isdigit(ch); ch=getchar()) x=x*10+ch-'0'; 24 return x*f; 25 } 26 void update(int p,int x) { 27 for (; p<=n; p+=p&(-p)) sum[p] += x; 28 } 29 int query(int p) { 30 int ans = 0; 31 for (; p>=1; p-=p&(-p)) ans += sum[p]; 32 return ans; 33 } 34 int main() { 35 n = read(); 36 for (int i=1; i<=n; ++i) 37 a[i].val = read(),a[i].pos = i; 38 sort(a+1,a+n+1); 39 int ans = 0; 40 for (int i=1; i<=n; ++i) { 41 ans += query(a[i].pos-1); 42 update(a[i].pos,1); 43 } 44 cout << ans; 45 return 0; 46 }
二分查找一个数,必须要排好序
1 int binary_search(int x,int y,int c) 2 { 3 int l,r,mid; 4 l = x; 5 r = y; 6 while (l<r) 7 { 8 mid = (l+r)>>1; 9 if (c<=a[mid]) r = mid; 10 else l = mid+1; 11 } 12 return l; 13 } 14 /*------------------------------------*/ 15 int find(int l,int r,int x) 16 { 17 while (l<=r) 18 { 19 int mid = (l+r)>>1; 20 if (a[mid]<=x) l = mid+1; 21 else r = mid-1; 22 } 23 return l; 24 }
等价于(stl):
1 lower_bound(a+x,a+y+1,c)-a;
快速排序
1 void qsort(int l,int r) 2 { 3 int i = l,j = r; 4 int mid = a[(l+r)>>1]; 5 while (i<=j) 6 { 7 while (a[i]<mid) i++; 8 while (a[j]>mid) j--; 9 if (i<=j) 10 { 11 int t = a[i]; a[i] = a[j]; a[j] = t; 12 i++; j--; 13 } 14 } 15 if (i<r) qsort(i,r); 16 if (l<j) qsort(l,j); 17 }
快速排序求第k大的数
1 int qsort(int *a,int l,int r) 2 { 3 int tmp = a[l],pos = l; 4 int i = l, j = r; 5 while (i<j) 6 { 7 while (i<j&&a[j]>tmp) j--; 8 if (i<j) 9 { 10 a[pos] = a[j]; 11 pos = j; 12 } 13 while (i<j&&a[i]<tmp) i++; 14 if (i<j) 15 { 16 a[pos] = a[i]; 17 pos = i; 18 } 19 } 20 a[pos] = tmp; 21 return pos; 22 } 23 int findkth(int *a,int n,int k) 24 { 25 int l = 0,r = n-1; 26 while (1) 27 { 28 int pos = qsort(a,l,r); 29 if (pos==n-k) return a[pos]; 30 else if (pos<n-k) l = pos+1; 31 else r = pos-1; 32 } 33 }
dfs序
1 void dfs(int u,int fa) { 2 q[++tot] = u; 3 L[u] = tot; 4 for (int i=head[u]; i; i=e[i].nxt) { 5 int v = e[i].to; 6 if (v==fa) continue; 7 dfs(v,u); 8 } 9 R[u] = tot; 10 }
生成下一个(前一个)排列
1 #include<iostream> 2 #include<algorithm> 3 #include<string> 4 5 using namespace std; 6 7 int main() 8 { 9 string s; 10 cin>>s; // 包括string类型,vector,还有数组(指针左闭右开) 11 sort(str.begin(), str.end()); 12 cout<<str<<endl; 13 while (next_permutation(str.begin(), str.end())) { // 返回bool类型, 14 cout << str << endl; 15 } 16 return 0; 17 } 18 // 相应的 前一个排列 pre_permutation
三分查找(求凸函数最大值的位置)
1 double search() { 2 while (r - l >= eps) { 3 lmid = (l + r) / 2.0; 4 rmid = (lmid + r) / 2.0; 5 if (f(lmid) >= f(rmid)) r = rmid; 6 else l = lmid; 7 } 8 return l; 9 }
集合hash,判断两个集合是否一样
1 uLL getkey() { 2 uLL a = (rand() << 15) | rand(); 3 uLL b = (rand() << 15) | rand(); 4 return a * b; 5 } 6 uLL init() { 7 for (int i=1; i<=MAX_NUM; ++i) Key[i] = init(); // 数字i的key 8 } 9 int gethash(int *A) { 10 uLL ans = 0; 11 for (int i=1; i<=n; ++i) ans = ans ^ Key[A[i]]; 12 return ans; 13 }
——————————————————————