【导航页/板子】板子库

yeyou26の板子库

持续更新 纯手敲 板子题已注明 可能存在引用互联网资源 仅供学习交流
にじげんさいこう! ( ‵▽′)ψ

数据结构

图论

网络流

Dinic

【模板】网络最大流

int edgeid=1,n,m,ans,cur[N],dis[N],st,ed,head[N];
queue<int> q;
struct edge {int v,w,nxt;} e[M*2];
inline void addedge(int u,int v,int w)
{
    edgeid++;
    e[edgeid].v=v;
    e[edgeid].w=w;
    e[edgeid].nxt=head[u];
    head[u]=edgeid;
}
bool Bfs()
{
    while(!q.empty()) q.pop();
    for(int i=1;i<=n;i++)
    {
        cur[i]=head[i]; //重置当前弧优化
        dis[i]=0; //重置距离
    }
    q.push(st);
    dis[st]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int v=e[i].v;
            if(e[i].w && !dis[v]) 
            {
                dis[v]=dis[u]+1;
                if(v==ed) return 1;
                q.push(v);
            }
        }
    }
    return 0;
}

int Dfs(int u,int rst)
{
    if(!rst || u==ed) return rst;
    int sum=0;
    for(int i=cur[u];i;i=e[i].nxt) //当前弧优化 确保时间复杂度O(n^2 m)
    {
        int v=e[i].v;
        cur[u]=i;
        int f;
        if(dis[v]==dis[u]+1 && (f=Dfs(v,min(rst,e[i].w))))
        {
            e[i].w-=f;
            e[i^1].w+=f;
            sum+=f;
            rst-=f;
            if(rst==0) break;//余量优化 常数
        }
    }
    if(sum==0) dis[u]=0;//废点优化 常数
    return sum;
}

void Dinic() {while(Bfs()) ans+=Dfs(1,INF);}

算法与思想

字符串

字符串最小表示法

【模板】最小表示法

int a[2*N];
int n;

void init()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        long long x;
        scanf("%d",&x);
        a[i]=a[i+n]=x;
    }
}

void solve()
{
    int i=1,j=2,k=0;
    while(i<=n && j<=n)
    {
        k=0;
        while(a[i+k]==a[j+k] && k<n) k++;
        if(a[i+k]>a[j+k]) i=i+k+1;
        else j=j+k+1;
        if(k==n) break;
        if(i==j) j++;
    }
    int ans=min(i,j);
    for(int p=1;p<=n;p++)
    {
        printf("%d ",a[ans+p-1]);
    }
}

字符串哈希

【模板】字符串哈希

const ull p=998244353;

string s;
ull now_hash,v[100005];
int cnt,ans,n;

void get_hash()
{
    now_hash=0;
    ull now_p=1;
    for(int i=1;s[i];i++)
    {
        now_hash+=s[i]*now_p;
        now_p*=p;
    }
}

void do_compare()
{
    bool flag=0;
    for(int i=1;i<=cnt;i++)
    {
        if(v[i]==now_hash)
        {
            flag=1;
            break;
        }
    }
    if(flag==0)
    {
        ans++;
        v[++cnt]=now_hash;
    }
}

void solve()
{
    for(int i=1;i<=n;i++)
    {
        cin>>s;
        get_hash();
        do_compare();
    }
    printf("%d",ans);
}

KMP

【模板】KMP

char p[1000005],s[1000005];
int lenp,lens;
int lst[1000005];

void init()
{
    cin>>(s+1)>>(p+1);
    lenp=strlen(p+1);
    lens=strlen(s+1);
}

void pre_work()
{
    lst[1]=0;
    for(int i=2,j=0;i<=lenp;i++)
    {
        while(j && p[j+1]!=p[i]) j=lst[j];
        if(p[j+1]==p[i]) j++;
        lst[i]=j;
    }
}

void kmp()
{
    for(int i=1,j=0;i<=lens;i++)
    {
        while(j && p[j+1]!=s[i]) j=lst[j];
        if(p[j+1]==s[i]) j++;
        if(j==lenp) printf("%d\n",i-j+1);
    }
}

void out_put()
{
    for(int i=1;i<=lenp;i++)
    {
        printf("%d ",lst[i]);
    }
}

扩展KMP(Z Function)

【模板】扩展 KMP/exKMP(Z 函数)

char a[N],b[N];
int p[N],z[N];
int lena,lenb;

void init()
{
    cin>>(a+1)>>(b+1);
    lena=strlen(a+1);
    lenb=strlen(b+1);
}

void get_z()
{
    z[1]=lenb;
    for(int i=2,l=0,r=0;i<=lenb;i++)
    {
        if(i<=r) z[i]=min(z[i-l+1],r-i+1);
        while(b[1+z[i]]==b[i+z[i]]) z[i]++;
        if(i+z[i]-1>r) l=i,r=i+z[i]-1;   
    }
}

void get_p()
{
    for(int i=1,l=0,r=0;i<=lena;i++)
    {
        if(i<=r) p[i]=min(z[i-l+1],r-i+1);
        while(i+p[i]<=lena && 1+p[i]<=lenb && a[i+p[i]]==b[1+p[i]]) p[i]++;
        if(i+p[i]-1>r) l=i,r=i+p[i]-1; 
    }
}

马拉车(Manacher)

【模板】manacher

int d[2*N];
char ipt[N];
char c[2*N];
int n;

void init()
{
    cin>>(ipt+1);
    c[0]='$';
    int k=1;
    c[k]='#';
    n=strlen(ipt+1);
    for(int i=1;i<=n;i++)
    {
        c[++k]=ipt[i],c[++k]='#';
    }
    n=k;
}

void Manacher()
{
    d[1]=1;
    for(int i=2,l,r=1;i<=n;i++)
    {
        if(i<=r) d[i]=min(d[r-i+l],r-i+1);
        while(c[i+d[i]]==c[i-d[i]]) d[i]++;
        if(r<i+d[i]-1) r=i+d[i]-1,l=i-d[i]+1;
    }
}

Trie字典树

int n,m,t[N][150],idx,cnt[N];

inline int trans(char c) {return c^64;}

void Insert(string s)
{
    int p=0;
    for(int i=0;s[i];i++)
    {
        int ch=trans(s[i]);
        if(!t[p][ch])
        {
            t[p][ch]=++idx;
        }
        p=t[p][ch];
    }
    cnt[p]++;
}

int Query(string s)
{
    int p=0;
    for(int i=0;s[i];i++)
    {
        int ch=trans(s[i]);
        if(!t[p][ch])
        {
            return 0;
        }
        else
        {
            p=t[p][ch];
        }
    }
    return cnt[p];
}

01异或树

int n,m,t[N][150],idx,cnt[N];

int trans(char c) {return c^64;}

void Insert(string s)
{
    int p=0;
    for(int i=0;s[i];i++)
    {
        int ch=trans(s[i]);
        if(!t[p][ch])
        {
            t[p][ch]=++idx;
        }
        p=t[p][ch];
    }
    cnt[p]++;
}

int Query(string s)
{
    int p=0;
    for(int i=0;s[i];i++)
    {
        int ch=trans(s[i]);
        if(!t[p][ch])
        {
            return 0;
        }
        else
        {
            p=t[p][ch];
        }
    }
    return cnt[p];
}

AC自动机

AC 自动机(简单版)

int t[(int)1e6+6][30],nxt[(int)1e6+5],idx,n;
string mainstring,ss[(int)1e6+6];

void init();
void Addtrie(string s);
void Trie();
queue<int> q;
void Aho_corasick();
int Query(string mainstring);

int main()
{
    init();
    Trie();
    Aho_corasick();
    cout<<Query(mainstring);
    return 0;
}

//Function Implementation

int Query(string s)
{
    int ans=0;
    int p=0;
    for(int i=0;s[i];i++)
    {
        int c=s[i]&31;
        p=t[p][c];
        for(int j=p;cnt[j]!=-1 && j;j=nxt[j])
        {
            ans+=cnt[j];
            cnt[j]=-1;
        }
    }
    return ans;
}

void Addtrie(string s)
{
    int p=0;
    for(int i=0;s[i];i++)
    {
        int c=s[i]&31;
        if(!t[p][c])
        {
        t[p][c]=++idx;
        }
        p=t[p][c];
    }
    cnt[p]++;
}

void Trie()
{
    for(int i=1;i<=n;i++)
    {
        Addtrie(ss[i]);
    }
}

void Aho_corasick()
{
    for(int i=1;i<=26;i++)
    {
        if(t[0][i]) q.push(t[0][i]);
    }
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=1;i<=26;i++)
        {
            int v=t[u][i];
            if(v)
            {
                nxt[v]=t[nxt[u]][i];
                q.push(v);
            }
            else 
            {
                t[u][i]=t[nxt[u]][i];
            }
        }
    }
}

void init()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>ss[i];
    }
    cin>>mainstring;
}

后缀数组(SA)

【模板】后缀排序

//额外数据测试lcp
//input:aabaaaab
//output:sa:4 5 6 1 7 2 8 3 
//      lcp:0 3 2 3 1 2 0 1 
#include<bits/stdc++.h>
using namespace std;

#define w where
const int N = (int)3e6;
int n,m=256;//后缀个数 桶个数(m初始值为值域(应该是吧))
int where[N];//第i个后缀在哪个桶里
int y[N];//临时数组
int c[N];//计数排序的计数数组
int sa[N];//排名为i的后缀
int rk[N];//第i个后缀的排名
int lcp[N];//排名为i的后缀跟排名为i-1的后缀的最长公共前缀的长度

char s[N];

void init();
void get_sa();
void get_lcp();

int main()
{
    init();
    get_sa();
    for(int i=1;i<=n;i++) printf("%d ",sa[i]);
    printf("\n");
    get_lcp();
    for(int i=1;i<=n;i++) printf("%d ",lcp[i]);
    return 0;
}

void init()
{
    cin>>(s+1);
    n=strlen(s+1);
}

//Function Implementation

void get_lcp()
{
    for(int i=1;i<=n;i++) rk[sa[i]]=i;
    for(int i=1,k=0;i<=n;i++) //枚举第i个后缀
    {
        if(rk[i]==1) continue;//排名为1的后缀的lcp=0
        if(k) k--; //定理:lcp[rk[i]]>=lcp[rk[i-1]]-1;
        int j=sa[rk[i]-1]; //从排名上看,i后缀的前临后缀j
        while(i+k<=n && j+k<=n && s[i+k]==s[j+k]) k++;//暴力枚举
        lcp[rk[i]]=k;
    }
}

void get_sa()
{
    //第一次计数排序,按第一个字母排
    for(int i=1;i<=n;i++) c[w[i]=s[i]]++;
    for(int i=1;i<=m;i++) c[i]+=c[i-1];
    for(int i=n;i>=1;i--) sa[c[w[i]]--]=i;
    for(int k=1;k<=n;k<<=1)
    {
        //按 后半段字符串 进行计数排序
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++) y[i]=sa[i];
        for(int i=1;i<=n;i++) c[w[y[i]+k]]++;
        for(int i=1;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i>=1;i--) sa[c[w[y[i]+k]]--]=y[i];
        //按 前半段字符串 进行计数排序
        memset(c,0,sizeof(c));
        for(int i=1;i<=n;i++) y[i]=sa[i];
        for(int i=1;i<=n;i++) c[w[y[i]]]++;
        for(int i=1;i<=m;i++) c[i]+=c[i-1];
        for(int i=n;i>=1;i--) sa[c[w[y[i]]]--]=y[i];
        //把排好序的 长度为2k的字符串 放到桶里 并 重新计算桶的个数
        m=0;
        for(int i=1;i<=n;i++) y[i]=w[i];
        for(int i=1;i<=n;i++)
        {
            if(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) w[sa[i]]=m;
            else w[sa[i]]=++m;
        }
        if(m==n) break; //桶个数跟后缀一样多,说明已经排好了
    }
}

后缀自动机(SAM)

【模板】后缀自动机(SAM)

//注意:这道题不是纯的后缀自动机,main函数有一点额外处理
#define ll long long
#define N (int(2e6+6))

int fa[N],ch[N][28],len[N],cnt[N],idx=1,np=1;
ll ans;
string s;
vector<int> e[N];

void Addsam(int c);
ll calculate();
void dfs(int u);

int main()
{
    freopen("working.in","r",stdin);
    freopen("working.out","w",stdout);
    cin>>s;
    for(int i=0;s[i];i++)
    {
        Addsam(s[i]&31);
    }
    for(int i=2;i<=idx;i++)
    {
        e[fa[i]].push_back(i);
    }
    dfs(1);
    cout<<ans;
    return 0;
}

//Function Implementation

void dfs(int u)
{
    for(int v : e[u])
    {
        dfs(v);
        cnt[u]+=cnt[v];
    }
    if(cnt[u]>1) ans=max(ans,(ll)cnt[u]*len[u]);
}

void Addsam(int c)
{
    //p回跳指针 np新节点 q链接点 nq分裂链接点
    int p=np,np=++idx;
    len[np]=len[p]+1;
    cnt[np]=1;
    for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
    //case 1 找不到任何出现过(新串后缀)
    if(p==0) fa[np]=1;
    else 
    {   
        int q=ch[p][c];
        //case 2 链接点合法,直接连
        if(len[q]==len[p]+1) fa[np]=q;
        else 
        {
            //case 3 链接点不合法,裂开为nq和q,q负责长度大于len(p)+1的串,nq负责长度小于等于len(p)+1的串
            int nq=++idx;
            len[nq]=len[p]+1;
            fa[nq]=fa[q];fa[q]=nq;fa[np]=nq;
            //指向q的转移边指向nq
            for(;p && ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            //从q出发的转移边丢给nq一份
            memcpy(ch[nq],ch[q],sizeof(ch[q]));  
        }
    }
}

数论/数学/计算几何

世界上最美的GCD

ll Gcd(ll x,ll y){while(y^=x^=y^=x%=y);return x;}

DP

排序

【模板】排序

快速排序

int a[N];
void Quicksort(int l,int r)
{
    if(l>=r) return ; 
    int i=l,j=r;
    int key=a[l];
    while(i<j)
    {
        while(i<j && a[j]>=key) j--;
        a[i]=a[j];
        while(i<j && a[i]<=key) i++;
        a[j]=a[i];
        a[i]=key;
    }
    Quicksort(l,i-1);
    Quicksort(i+1,r);
}

归并排序

int a[N],b[N],cnt;
void Mergesort(int l,int r)
{
    if(l>=r) return ;
    int mid=(l+r)>>1;
    Mergesort(l,mid);
    Mergesort(mid+1,r);
    int i=l,j=mid+1,k=l;
    while(i<=mid && j<=r)
    {
        if(a[i]<=a[j]) b[k++]=a[i++];
        else b[k++]=a[j++],cnt+=mid-i+1;
    }  
    while(i<=mid) b[k++]=a[i++];
    while(j<=r) b[k++]=a[j++];
    for(int i=l;i<=r;i++) a[i]=b[i];
}

其他

快读/快写

A+B Problem

lll Read()
{
    bool flag=0;
    char ch=getchar();
    lll ans=0;
    while(!isdigit(ch) && ~ch)
    {
        flag|=(ch=='-');
        ch=getchar();
    }
    while(isdigit(ch) && ~ch)
    {
        ans=(ans<<1)+(ans<<3)+(ch^48);
        ch=getchar();
    }
    return flag ? -ans : ans;
}

int _c[100];
void Write(lll x)
{
    int i=0;
    bool flag=0;
    if(x<0) {x=-x;putchar('-');}
    if(x==0) putchar('0');
    while(x) {_c[++i]=x%10;x/=10;}
    while(i) {putchar(_c[i--]^48);}
}
posted @ 2024-01-25 17:16  yeyou26  阅读(69)  评论(0)    收藏  举报