一些模板(后缀数组+虚树+辛普森积分+凸包+博弈论搜索+矩阵求逆+高斯消元+半平面交+LCT基本操作+状态压缩+序列自动机+后缀自动机+三模数NTT+FWT+分治FFT+Pollard Rho质因数)

这里贴一些不太熟的板子,方便以后复习,有空再来加点注释。

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;
}

#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; 
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值