(长期更新)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常用模板的主要内容,如果未能解决你的问题,请参考以下文章

js常用代码片段(更新中)

css常用代码片段 (更新中)

OI实用工具 持续更新ing

[长期更新]模板&算法学习情况

OI模板合集(数据结构图论数论)

常用工具类-----长期更新