这里贴一些不太熟的板子,方便以后复习,有空再来加点注释。
1、后缀数组
(感觉我的板子还是挺优美的 (⊙∀⊙) ( ⊙ ∀ ⊙ ) 嗯)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 200005
int SA[N],rank[N],height[N],tax[N],tp[N],a[N],n,m;
char ch[N],ALL[N],st[N];
void Rsort()
{
for (int i=0;i<=m;i++) tax[i]=0;
for (int i=1;i<=n;i++) tax[rank[tp[i]]]++;
for (int i=1;i<=m;i++) tax[i]+=tax[i-1];
for (int i=n;i>=1;i--) SA[tax[rank[tp[i]]]--]=tp[i];
/* an di yi guan jian zi pai xu ,
di er guan jian zi pai ming kao hou de hou zhui
you xian bei fang dao hou mian*/
}
int cmp(int *f,int x,int y,int w)
{
return f[x]==f[y]&&f[x+w]==f[y+w];
}
void Suffix()
{
for (int i=1;i<=n;i++) rank[i]=a[i],tp[i]=i;
m=127; Rsort();
for (int w=1,p=1,i;p<n;w+=w,m=p)
{
for (p=0,i=n-w+1;i<=n;i++) tp[++p]=i;
for (i=1;i<=n;i++) if (SA[i]>w) tp[++p]=SA[i]-w;
Rsort(),swap(rank,tp),rank[SA[1]]=p=1;
for (i=2;i<=n;i++)
rank[SA[i]]=cmp(tp,SA[i],SA[i-1],w)?p:++p;
}
int j,k=0;
for (int i=1;i<=n;height[rank[i++]]=k)
for (k=k?k-1:k,j=SA[rank[i]-1];a[i+k]==a[j+k];++k);
}
int main()
{
scanf("%s",st);
n=strlen(st);
for (int i=0;i<n;i++) a[i+1]=st[i];
Suffix();
for (int i=1;i<=n;i++) printf("%d ",SA[i]); printf("\n");
for (int i=1;i<=n;i++) printf("%d ",height[i]);
return 0;
}
2、建虚树
(加了点注释,加“?”的地方不确定对不对(⊙o⊙),看到的dalao们可以顺便解答下嘛~(虽然BLOG万年没更新,大概不会有人看了┭┮﹏┭┮……))
void build_vtree()
{
sort(h+1,h+m+1,cmp); //按dfn排序
tot=0; top=0; sta[++top]=1; head[1]=0; //1是虚树的根?
for (int i=1+(h[1]==1);i<=m;i++)
{
int lca=LCA(h[i],sta[top]); //栈顶和新加入节点的lca
if (lca!=sta[top])
{
while (dfn[sta[top-1]]>dfn[lca]) //要开辟一条更右的树杈?
{
push(sta[top],sta[top-1]); //原先维护的最右链连起来
top--;
}
if (dfn[sta[top-1]]<dfn[lca]) //lca需要加进虚树中
{
head[lca]=0;
push(sta[top],lca);
sta[top]=lca;
}
else push(sta[top--],lca);
}
head[h[i]]=0;
sta[++top]=h[i];
}
for (int i=1;i<top;i++) push(sta[i],sta[i+1]);
}
3、辛普森积分
DB f(DB X) //求高度
{
DB h=0;
/*......*/
return h;
}
DB simpson(DB a,DB b,DB fa,DB fb,DB fm)
{
return (b-a)/6*(fa+4*fm+fb);
}
DB area(DB l,DB fl,DB m,DB fm,DB r,DB fr,DB pre)
{
DB ls=(l+m)/2,rs=(m+r)/2,fls=f(ls),frs=f(rs);
DB la=simpson(l,m,fl,fm,fls),ra=simpson(m,r,fm,fr,frs);
if (fabs(la+ra-pre)<eps) return pre;
return area(l,fl,ls,fls,m,fm,la)+area(m,fm,rs,frs,r,fr,ra);
}
4、O(n log n)求凸包
#define sqr(x) ((x)*(x))
struct point{
double x,y;
point (double _x=0,double _y=0) { x=_x; y=_y; }
}p[1005],sta[1005];
double dis(point a,point b) { return sqr(a.x-b.x)+sqr(a.y-b.y); }
point operator - (point a,point b) { return point(a.x-b.x,a.y-b.y); }
double operator *(point a,point b) { return a.x*b.y-a.y*b.x; }
bool operator < (point a,point b)
{
double t=(a-p[1])*(b-p[1]);
return (t>0)||(t==0&&dis(p[1],a)<dis(p[1],b));
}
int convex_hull() //返回凸包上点的个数
{
int k=1,top=0;
for (int i=2;i<=n;i++) //找最左下的点
if ((p[i].y<p[k].y)||(p[i].y==p[k].y&&p[i].x<p[k].x)) k=i;
swap(p[k],p[1]);
sort(p+2,p+n+1); //按极角排序
sta[++top]=p[1]; sta[++top]=p[2];
for (int i=3;i<=n;i++)
{
while (top>1&&(sta[top]-sta[top-1])*(p[i]-sta[top-1])<=0)
top--;
sta[++top]=p[i];
}
sta[top+1]=p[1];
return top;
}
5、博弈论搜索
int dfs(int now)
{
if (SG[now]!=-1) return SG[now];
bool used[1005]; memset(used,false,sizeof(used));
for (int i=head[now];i;i=e[i].ne) used[dfs(e[i].to)]=true;
for (int i=0;;i++) if(!used[i]) { SG[now]=i; break; }
return SG[now];
}
6、矩阵求逆
(这份板子是模意义下的矩阵求逆,还附了矩阵hash)
struct Matrix{
int a[75][75];
Matrix() { memset(a,0,sizeof(a)); }
inline void readM()
{
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
a[i][j]=read();
}
inline ull hash() // +变成^
{
ull s=1,ret=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
ret^=(s*a[i][j]),s*=seed;
return ret;
}
inline Matrix get_inv() //需要求逆元的矩阵右边拼一个单位矩阵之后高斯消元,右边得到的就是逆矩阵
{
static int b[75][150];
memset(b,0,sizeof(b));
for (int i=1;i<=n;i++)
{
b[i][n+i]=1;
for (int j=1;j<=n;j++)
b[i][j]=a[i][j];
}
for (int i=1;i<=n;i++)
{
for (int j=i+1;j<=n*2;j++)
(b[i][j]*=inv[b[i][i]])%=p;
b[i][i]=1;
for (int j=i+1;j<=n;j++)
for (int t=b[j][i],k=i;k<=n*2;k++)
b[j][k]=((b[j][k]-t*b[i][k])%p+p)%p;
}
for (int i=n;i>=1;i--)
for (int j=i+1;j<=n;j++)
for (int t=b[i][j],k=j;k<=2*n;k++)
b[i][k]=((b[i][k]-t*b[j][k])%p+p)%p;
Matrix ret;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
ret.a[i][j]=b[i][j+n];
return ret;
}
inline Matrix operator * (const Matrix &b) const
{
Matrix ret;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
for (int k=1;k<=n;k++)
ret.a[i][j]=(ret.a[i][j]+a[i][k]*b.a[k][j])%p;
return ret;
}
inline void operator *= (const Matrix b)
{
Matrix tmp=*this;
*this=tmp*b;
}
}
7、看到一种更短的高斯消元
void gauss()
{
double w;
for (int i=1;i<=siz;i++)
{
for (int j=i+1;j<=siz;j++)
{
w=-f[j][i]/f[i][i];
for (int k=1;k<=siz+1;k++)
f[j][k]+=w*f[i][k];
}
for (int j=i-1;j>=1;j--)
{
w=-f[j][i]/f[i][i];
for (int k=1;k<=siz+1;k++)
f[j][k]+=w*f[i][k];
}
}
for (int j=1;j<=siz;j++) f[j][siz+1]/=f[j][j];
}
8、半平面交
(zzy排序增量算法优化 O(n log n))
#define N 505
typedef double db;
struct P{
db x,y;
P(db _x=0.0,db _y=0.0) { x=_x; y=_y; }
P operator + (const P a) const { return P(x+a.x,y+a.y); }
P operator - (const P a) const { return P(x-a.x,y-a.y); }
P operator * (const db k) const { return P(x*k,y*k); }
db operator * (const P a) const { return x*a.y-y*a.x; }
db operator / (const P a) const { return x*a.x+y*a.y; }
}a[N];
struct L{
P x,y,v; db ang;
L(){}
L(P _x,P _y,P _v) { x=_x; y=_y; v=_v; ang=atan2(v.y,v.x); }
bool operator < (const L a) const { return ang<a.ang||ang==a.ang&&v*(a.y-x)>0; }
friend P inter(L a,L b)
{
P nw=b.x-a.x; db t=(nw*a.v)/(a.v*b.v);
return b.x+b.v*t;
}
friend bool jud(P a,L b) { return b.v*(a-b.x)<0; }
// 这里默认半平面为直线方向向量的逆时针一侧,jud为true表示点不在半平面内
}l[N],q[N];
int HPO(int cnt)
{
int tot=0;
sort(l+1,l+cnt+1);
for (int i=1;i<=cnt;i++)
{
if (l[i].ang!=l[i-1].ang) ++tot;
l[tot]=l[i];
}
cnt=tot; tot=0;
int tou=1,wei=2; q[1]=l[1]; q[2]=l[2];
for (int i=3;i<=cnt;i++)
{
while (tou<wei&&jud(inter(q[wei-1],q[wei]),l[i])) wei--;
while (tou<wei&&jud(inter(q[tou+1],q[tou]),l[i])) tou++;
q[++wei]=l[i];
}
while (tou<wei&&jud(inter(q[wei-1],q[wei]),q[tou])) wei--;
while (tou<wei&&jud(inter(q[tou+1],q[tou]),q[wei])) tou++;
q[wei+1]=q[tou];
for (int i=tou;i<=wei;i++) a[++tot]=inter(q[i],q[i+1]);
return tot;
}
9、Link-Cut Tree基本操作
#define N 300005
struct node{
int ch[2];
}T[N];
int fa[N];
int pd(int x)
{
if (x==T[fa[x]].ch[0]) return 0;
if (x==T[fa[x]].ch[1]) return 1; return -1;
}
void update(int x)
{
int ls=T[x].ch[0],rs=T[x].ch[1];
if (!ls&&!rs)
{
/* ······ */
return;
}
if (ls&&rs)
{
/* ······ */
}
else
{
if (ls)
{
/* ······ */
}
else
{
/* ······ */
}
}
}
void split(int x)
{
int y=T[x].ch[1];
/* ······ */
T[x].ch[1]=0; update(x);
}
void merge(int x,int y)
{
/* ······ */
T[x].ch[1]=y; update(x);
}
void rotate(int x)
{
int y=fa[x],z=fa[y],tx=pd(x),ty=pd(y);
if (~ty) T[z].ch[ty]=x; fa[x]=z;
if (T[x].ch[tx^1]) fa[T[x].ch[tx^1]]=y; T[y].ch[tx]=T[x].ch[tx^1];
T[x].ch[tx^1]=y; fa[y]=x;
update(y); update(x); if (~ty) update(z);
}
void splay(int x)
{
while (~pd(x))
{
if (~pd(fa[x]))
{
if (pd(fa[x])==pd(x)) rotate(fa[x]);
else rotate(x);
}
rotate(x);
}
}
void access(int x)
{
splay(x);
if (T[x].ch[1]) split(x);
while (fa[x])
{
int y=fa[x]; splay(y);
if (T[y].ch[1]) split(y);
merge(y,x); update(x); x=y;
}
}
10、状态压缩
long long hsh()
{
long long ret=0;
for (int i=1;i<=n;i++) ret=ret*seed+now[i];
return ret;
}
void uzip(long long sta)
{
for (int i=n;i>=1;i--) now[i]=sta%seed,sta/=seed;
}
11、序列自动机
void build()
{
n=strlen(t+1)
for (int i=1;i<=n;i++) //序列自动机
{
int c=t[i]-'a';
for (int j=i-1;j>=pre[c];j--) to[j][c]=i;
pre[c]=i;
}
}
12、后缀自动机
#define N 2005
int n,fa[N],l[N],pre[N],to[N][27],tax[N],id[N];
int p,np,q,nq,las=1,cnt=1;
char t[N];
void extend(int c)
{
p=las; np=las=++cnt; l[np]=l[p]+1;
while (p&&!to[p][c]) to[p][c]=np,p=fa[p];
if (!p) fa[np]=1;
else
{
int q=to[p][c];
if (l[q]==l[p]+1) fa[np]=q;
else
{
nq=++cnt; l[nq]=l[p]+1;
memcpy(to[nq],to[q],sizeof to[q]);
fa[nq]=fa[q]; fa[q]=fa[np]=nq;
while (p&&to[p][c]==q) to[p][c]=nq,p=fa[p];
}
}
}
void build()
{
n=strlen(t+1);
for (int i=1;i<=n;i++) extend(t[i]-'a'); //构造
for (int i=1;i<=cnt;i++) tax[l[i]]++; //拓扑排序
for (int i=1;i<=m;i++) tax[i]+=tax[i-1];
for (int i=cnt;i>=1;i--) id[tax[l[i]]--]=i;
}
13、三模数NTT
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 300005
using namespace std;
inline int read()
{
char c=getchar(); int num=0,f=1;
while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
while (c<='9'&&c>='0') { num=num*10+c-'0'; c=getchar(); }
return num*f;
}
const int m1=469762049,m2=998244353,m3=1004535809,g=3;
const long long M=1ll*m1*m2;
int n,m,r[N],a[N],b[N],c[N],d[N],ans[3][N],mod;
int ksm(int a,int b,int p)
{
int ret=1;
for (;b;b>>=1,a=1ll*a*a%p)
if (b&1) ret=1ll*ret*a%p;
return ret;
}
long long ksc(long long a,long long b,long long p)
{
long long ret=0;
for (;b;b>>=1,a=(1ll*a+1ll*a)%p)
if (b&1) ret=(1ll*ret+1ll*a)%p;
return ret;
}
void ntt(int n,int *a,int f,int mod)
{
for (int i=0;i<n;i++) if (i<r[i]) swap(a[i],a[r[i]]);
for (int k=1;k<n;k<<=1)
{
int wn=ksm(g,(mod-1)/(k<<1),mod);
for (int i=0;i<n;i+=(k<<1))
for (int j=0,w=1;j<k;j++,w=1ll*w*wn%mod)
{
int x=a[i+j],y=1ll*a[i+j+k]*w%mod;
a[i+j]=(x+y)%mod;
a[i+j+k]=(x-y+mod)%mod;
}
}
if (f==-1)
{
int invn=ksm(n,mod-2,mod); a[0]=1ll*a[0]*invn%mod;
for (int i=1;i<=n/2;i++)
{
a[i]=1ll*a[i]*invn%mod;
if (i!=n-i) a[n-i]=1ll*a[n-i]*invn%mod;
swap(a[i],a[n-i]);
}
}
}
int main()
{
n=read(); m=read(); mod=read();
for (int i=0;i<=n;i++) a[i]=read();
for (int i=0;i<=m;i++) b[i]=read();
int fn=1,L=0; while (fn<=n+m) fn<<=1,L++;
for (int i=0;i<fn;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
copy(a,a+n+1,c); copy(b,b+m+1,d);
ntt(fn,c,1,m1); ntt(fn,d,1,m1);
for (int i=0;i<fn;i++) ans[0][i]=1ll*c[i]*d[i]%m1;
memset(c,0,sizeof(c)); memset(d,0,sizeof(d));
copy(a,a+n+1,c); copy(b,b+m+1,d);
ntt(fn,c,1,m2); ntt(fn,d,1,m2);
for (int i=0;i<fn;i++) ans[1][i]=1ll*c[i]*d[i]%m2;
memset(c,0,sizeof(c)); memset(d,0,sizeof(d));
copy(a,a+n+1,c); copy(b,b+m+1,d);
ntt(fn,c,1,m3); ntt(fn,d,1,m3);
for (int i=0;i<fn;i++) ans[2][i]=1ll*c[i]*d[i]%m3;
ntt(fn,ans[0],-1,m1); ntt(fn,ans[1],-1,m2); ntt(fn,ans[2],-1,m3);
for (int i=0;i<=n+m;i++)
{
long long A=(ksc(1ll*ans[0][i]*m2%M,ksm(m2%m1,m1-2,m1),M)
+ksc(1ll*ans[1][i]*m1%M,ksm(m1%m2,m2-2,m2),M))%M;
long long k=((ans[2][i]-A)%m3+m3)%m3*ksm(M%m3,m3-2,m3)%m3;
printf("%d ",((k%mod)*(M%mod)%mod+A%mod)%mod);
}
return 0;
}
14、FWT
void fwt(int a[],int len,int f)
{
for (int i=2;i<=len;i<<=1)
for (int j=0;j<len;j+=i)
for (int k=j;k<j+(i>>1);k++)
{
int u=/*···*/,v=/*···*/;
if (f==1) a[k]=/*···*/,a[k+(i>>1)]=/*···*/;
else a[k]=/*···*/,a[k+(i>>1)]=/*···*/;
}
}
15、分治FFT
const double PI=acos(-1.0);
struct num{
double r,i;
num(double _r=0,double _i=0) { r=_r; i=_i; }
num operator + (const num a) const { return num(r+a.r,i+a.i); }
num operator - (const num a) const { return num(r-a.r,i-a.i); }
num operator * (const num a) const
{
return num(r*a.r-i*a.i,r*a.i+i*a.r);
}
}a[N<<2],b[N<<2];
int n,rev[N<<2];
void fft(num *a,int len,int f)
{
for (int i=0;i<len;i++) if (i<rev[i]) swap(a[i],a[rev[i]]);
for (int i=2;i<=len;i<<=1)
{
num wn(cos(-f*2*PI/i),sin(-f*2*PI/i));
for (int j=0;j<len;j+=i)
{
num w=num(1,0);
for (int k=j;k<j+(i>>1);k++,w=w*wn)
{
num x=a[k],y=a[k+(i>>1)]*w;
a[k]=x+y; a[k+(i>>1)]=x-y;
}
}
}
if (f==-1) for (int i=0;i<len;i++) a[i].r/=len*1.0;
}
void cdq(int l,int r)
{
if (l==r) { /*...*/ return; }
int mid=l+r>>1;
cdq(l,mid);
int len=1,L=0; while (len<=r-l+1) len<<=1,L++;
for (int i=0;i<=len;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));
for (int i=0;i<len;i++) a[i]=b[i]=num();
for (int i=l;i<=mid;i++) a[i-l]=/*...*/;
for (int i=0;i<r-l+1;i++) b[i]=/*...*/;
fft(a,len,1); fft(b,len,1);
for (int i=0;i<len;i++) a[i]=a[i]*b[i];
fft(a,len,-1);
for (int i=mid+1;i<=r;i++) dp[i]=/*...*/;
cdq(mid+1,r);
}
16、Pollard Rho质因数分解
#include<map>
typedef long long LL;
const int P[]={2,3,5,7,11,13,17,19,23,29};
map<LL,int> ans;
void insert(LL d) { if (!ans.count(d)) ans[d]=0; ++ans[d]; }
LL gcd(LL a,LL b)
{
while (b) { LL r=a%b; a=b; b=r; } return a;
}
LL ksc(LL a,LL b,LL p)
{
LL ret=0;
for (;b;b>>=1,a=(a+a)%p)
if (b&1) ret=(ret+a)%p;
return ret;
}
LL ksm(LL a,LL b,LL p)
{
LL ret=1;
for (;b;b>>=1,a=ksc(a,a,p))
if (b&1) ret=ksc(ret,a,p);
return ret;
}
LL check(LL n,LL s,LL t,LL a) //二次探测原理
{
LL x=ksm(a,s,n);
if (x==1) return true;
while (t--)
{
LL y=ksc(x,x,n);
if (y==1) return x==n-1;
x=y;
}
return false;
}
LL MR(LL n) //Millar Rabin 算法判断质数
{
LL s=n-1,t=0;
while (s%2==0) s/=2,t++;
for (int i=0;i<10;i++)
{
LL x=P[i];
if (n%x==0) return n==x;
if (!check(n,s,t,x)) return false;
}
return true;
}
LL PR(LL n,LL c) //寻找n的一个因子
{
LL x=1,y=(ksc(x,x,n)+c)%n;
while (x!=y)
{
LL d=gcd(abs(x-y),n); if (d>1) return d;
x=(ksc(x,x,n)+c)%n;
y=(ksc(y,y,n)+c)%n;
y=(ksc(y,y,n)+c)%n;
}
return n;
}
void divide(LL n)
{
if (n==1) return;
if (MR(n)) { insert(n); return; }
LL c=2;
while (1)
{
LL d=PR(n,c);
if (d!=n) { divide(d); divide(n/d); return; }
++c;
}
}