(长期更新)OI常用模板
Posted TianyiQ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(长期更新)OI常用模板相关的知识,希望对你有一定的参考价值。
看不惯我码风的同志请见谅……
DFT 离散傅立叶变换
void dft(pdd *a,int l,bool r){
int i,j=l/2,k;
for(i=1;i<l;++i){
if(i<j) swap(a[i],a[j]);
for(k=l/2;j&k;k>>=1) j^=k;
j^=k;
}
for(i=1;(1<<i)<=l;++i){
int cl=(1<<i);
pdd w=mpr(cos(2.0*pi/(double)cl),sin(2.0*pi/(double)cl));
if(r) w.second=-w.second;
for(j=0;j*cl<l;++j){
pdd cur=mpr(1.0,0.0);
for(k=0;k<(cl>>1);++k){
pdd v1=a[j*cl+k],v2=a[j*cl+k+(cl>>1)]*cur;
a[j*cl+k]=v1+v2;
a[j*cl+k+(cl>>1)]=v1-v2;
cur=cur*w;
}
}
}
}
hint: 参数 bool r 表示是否在进行逆向的 DFT(即是否是在插值)
hint2: pdd 是手写的 complex 类
NTT 快速数论变换
const int MOD=998244353,G=3;
const int MOD2=1004535809,G2=3;
const int MOD3=65537,G3=3;
void ntt(int *a,int l,bool r){
int i,j=l/2,k;
for(i=1;i<l;++i){
if(i<j) swap(a[i],a[j]);
for(k=l/2;j&k;k>>=1) j^=k;
j^=k;
}
for(i=1;(1<<i)<=n;++i){
int cl=(1<<i);
int w=pow(G,(MOD-1)/cl);
if(r) w=pow(w,MOD-2);
for(j=0;j*cl<n;++j){
int cur=1;
for(k=0;k<(cl>>1);k++){
int v1=a[j*cl+k],v2=((LL)a[j*cl+k+(cl>>1)]*(LL)cur)%MOD;
a[j*cl+k]=(v1+v2)%MOD;
a[j*cl+k+(cl>>1)]=(v1-v2+MOD)%MOD;
cur=((LL)cur*(LL)w)%(LL)MOD;
}
}
}
}
// instead of dividing all numbers by SZ in DFT, in NTT we multiply all numbers by inv(SZ).
hint: pow(A,B)=A^B
SAM 后缀自动机
struct node{
node *nxt[ALPHABET],*fa;
int mxv;
node(){
mxv=0;
fa=0;
memset(nxt,0,sizeof(nxt));
}
}*last,*root;
void extend(int v){
node *p=last,*np=new node;
np->mxv=p->mxv+1;
for(;p && !p->nxt[v];p=p->fa) p->nxt[v]=np;
if(!p) np->fa=root;
else{
node *q=p->nxt[v];
if(q->mxv==p->mxv+1){
np->fa=q;
}
else{
node *nq=new node;
nq->mxv=p->mxv+1;
memcpy(nq->nxt,q->nxt,sizeof(q->nxt));
nq->fa=q->fa;
q->fa=np->fa=nq;
for(;p && p->nxt[v]==q;p=p->fa) p->nxt[v]=nq;
}
}
last=np;
}
SA&LCP 后缀数组全家桶
void bsort(){
int i;
memset(cnt,0,sizeof(cnt));
for(i=0;i<n;++i) ++cnt[vy[i]];
for(i=1;i<=n+3 || i<=30;++i) cnt[i]+=cnt[i-1];
for(i=n-1;i>=0;--i) tmp[--cnt[vy[i]]]=i;
memset(cnt,0,sizeof(cnt));
for(i=0;i<n;++i) ++cnt[rk[tmp[i]]];
for(i=1;i<=n+3 || i<=30;++i) cnt[i]+=cnt[i-1];
for(i=n-1;i>=0;--i) ls[--cnt[rk[tmp[i]]]]=tmp[i];
memset(tmp,0,sizeof(tmp));
}
void getsa(){
int i,j,cv;
memset(rk,0,sizeof(rk));
memset(vy,0,sizeof(vy));
for(i=0;i<n;++i) {
rk[i]=s[i]-‘a‘+1;
}
for(i=2;i<=n*2;i<<=1){
for(j=0;j<n;++j){
vy[j]=rk[j+(i>>1)];
}
bsort();
cv=1;
for(j=0;j<n;++j){
if(j && (rk[ls[j-1]]!=rk[ls[j]]||vy[ls[j-1]]!=vy[ls[j]]))
++cv;
tmp[ls[j]]=cv;
}
memcpy(rk,tmp,sizeof(tmp));
}
}
void getlcp(){
int i,j,lv=0;
for(i=0;i<n;++i){
if(rk[i]==1) continue;
int la=ls[rk[i]-2];
for(j=MAX(0,lv-2);la+j<n&&i+j<n;++j){
if(s[la+j]!=s[i+j]) break;
}
lcp[i]=lv=j;
}
}
hint: vy=value_Y 意为第二排序准则
hint2: rk=rank lv=last_value ls=list
hint3: 可能是因为我的写法太鬼畜了,这段代码里改动几乎任何一处看似无关紧要的细节都会GG……别问我为什么
点分治
void getcen(int ver,int fa,int ts){
int i,j,k,cv=ts-sz[ver];
for(i=0;i<(int)adj[ver].size();++i){
if(adj[ver][i]!=fa && !del[adj[ver][i]]){
UMAX(cv,sz[adj[ver][i]]);
getcen(adj[ver][i],ver,ts);
}
}
UMIN(cur,mpr(cv,ver));
}
void deepin(int ver,int fa){
int i,j,k;
sz[ver]=1;
for(i=0;i<(int)adj[ver].size();++i){
if(!del[adj[ver][i]] && adj[ver][i]!=fa){
deepin(adj[ver][i],ver);
sz[ver]+=sz[adj[ver][i]];
}
}
}
int centroid(int ver){
cur=mpr(iinf,-1);
getcen(ver,-1,sz[ver]);
return cur.second;
}
void solve(int ver){
del[ver]=1;
int i,j,k;
for(i=0;i<(int)adj[ver].size();++i){
if(!del[adj[ver][i]]){
deepin(adj[ver][i],ver);
}
}
for(i=0;i<(int)adj[ver].size();++i){
if(!del[adj[ver][i]]){
solve(centroid(adj[ver][i]));
}
}
}
solve(0);
hint: cv=current_value sz=size
线性基
struct base{
int arr[35],got[35];
void init(){
memset(arr,0,sizeof(arr));
memset(got,0,sizeof(got));
}
void insert(int v){
int i,j;
for(i=0;i<31;++i){
if(v&(1<<i)) got[i]=1;
}
for(i=30;i>=0;--i){
if(v&(1<<i)){
if(arr[i])
v^=arr[i];
else{
for(j=i-1;j>=0;--j) if(v&(1<<j)) v^=arr[j];
for(j=i+1;j<31;++j) if(arr[j]&(1<<i)) arr[j]^=v;
arr[i]=v;
}
}
}
}
};
以上是关于(长期更新)OI常用模板的主要内容,如果未能解决你的问题,请参考以下文章