模板

一.字符串

0.hash

没学过hash,从头到尾什么都不会

1.kmp

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48) ;
    if(f)x=-x;
}

const int maxn=1e6+6;
int n,m,p[maxn];
char s[maxn],ss[maxn];

inline void pre()
{
    int j=0;
    p[0]=-1;
    inc(i,0,m-1)
    {
        j=p[i];
        while(j!=-1&&ss[i]!=ss[j])j=p[j];
        p[i+1]=((~j)?(ss[i]==ss[j]?++j:0):0);
    }
}

inline void kmp()
{
    int j=0;
    inc(i,0,n-1)
    {
        while(j!=-1&&s[i]!=ss[j])j=p[j];
        ++j;
        if(j==m)
        {
            printf("%d\n",i+1-j+1);
            j=p[j];
        }
    }
}
int main()
{
    freopen("a.in","r",stdin);
    scanf("%s%s",s,ss);
    n=strlen(s);m=strlen(ss);
    pre();
    kmp();
    inc(i,1,m)
    printf("%d ",p[i]);
    re 0;
 } 
View Code

2.trie

01trie

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48) ;
    if(f)x=-x;
}

const int maxn=1e5+5;
int n,m,hd[maxn];
struct node{
    int to,nt,val;
}e[maxn<<1];
int k;
inline void add(int x,int y,int z)
{
    e[++k]=(node){y,hd[x],z};hd[x]=k;
}

int dis[maxn];
inline void dfs(int x,int fa)
{
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v==fa)continue;
        dis[v]=dis[x]^e[i].val;
        dfs(v,x);
    }
}

#define dec(i,l,r) for(int i=l;i>=r;--i)

int tr[maxn*30][2],tot,ans;
inline void insert(int x)
{
    int u=0;
    dec(i,30,0)
    {
        int now=(x>>i)&1;
        if(!tr[u][now])tr[u][now]=++tot;
        u=tr[u][now];
    }
}
inline void find(int x)
{
    int u=0;
    int cnt=0;
    dec(i,30,0)
    {
        int now=(x>>(i))&1;
        if(tr[u][now^1])
        {
            cnt+=1<<i;
            u=tr[u][now^1];
        }
        else u=tr[u][now];
    }
    ans=max(ans,cnt);
}

int main()
{
    freopen("a.in","r",stdin);
    rd(n);
    int x,y,z;
    inc(i,2,n)
    {
        rd(x),rd(y),rd(z);
        add(x,y,z);
        add(y,x,z);
    }
    dfs(1,0);
    inc(i,1,n)
    {
        find(dis[i]);
        insert(dis[i]);
    }
    printf("%d",ans);
    re 0;
}
View Code

trie的字符版就看看ac自动机就好了

3.ac自动机

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=1e6+6;
int n,m,tr[maxn][26],tot,ed[maxn];
char s[maxn];
inline void insert()
{
    int len=strlen(s+1),u=0,x;
    inc(i,1,len) 
    {
        x=s[i]-'a';
        if(!tr[u][x])tr[u][x]=++tot;
        u=tr[u][x];
    }
    ++ed[u];
}

int fail[maxn*26];
inline void Get_fail()
{
    int u=0;
    queue<int>q;
    inc(i,0,25)if(tr[u][i])q.push(tr[u][i]);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        inc(i,0,25)
        if(tr[u][i])
        fail[tr[u][i]]=tr[fail[u]][i],q.push(tr[u][i]);
        else tr[u][i]=tr[fail[u]][i];
    }
    re ;
}

int ans;
inline void Get_A()
{
    int len=strlen(s+1);
    int u=0;
    inc(i,1,len)
    {
        int x=s[i]-'a';
        u=tr[u][x];
        for(int t=u;t&&ed[t]!=-1;t=fail[t])    
            ans+=ed[t],ed[t]=-1;
    }
}

int main()
{
    freopen("a.in","r",stdin);
    rd(n);
    inc(i,1,n)
    {
        scanf("%s",s+1);
        insert();
    }
    
    Get_fail();
    scanf("%s",s+1);
    Get_A();
    printf("%d",ans);
    re 0;
}
View Code

4.manacher

二.图论

1.最小生成树

Kruskal算法

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=5e3+3,maxm=2e5+5;

int n,m;
struct node{
    int fr,to,val;
    inline bool operator<(node b)const {
        re val<b.val;
    }
}e[maxm<<1];
int k,fa[maxn];
inline void add(int x,int y,int z){e[++k]=(node){x,y,z};}

inline int find(int x){
    re fa[x]==x?x:fa[x]=find(fa[x]);
}
int main()
{
    freopen("a.in","r",stdin);
    rd(n),rd(m);
    int x,y,z;
    inc(i,1,m)
    {
        rd(x),rd(y),rd(z);
        add(x,y,z);
    }
    sort(e+1,e+k+1);
    
    inc(i,1,n)fa[i]=i;
    int cnt=0,ans=0;
    inc(i,1,k)
    {
        int x=find(e[i].fr),y=find(e[i].to);
        if(x!=y)
        {
            fa[x]=y;
            ans+=e[i].val;
            ++cnt;
            if(cnt==n-1)break;
        }
    }
    if(cnt==n-1)printf("%d",ans);
    else puts("-1");
    re 0;
}
View Code

prim算法

适合稠密图的prim

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=5e3+3,maxm=2e5+5;
int inf=5e8;
int n,m,d[maxn][maxn],dis[maxn],vis[maxn];
int main()
{
    freopen("a.in","r",stdin);
    rd(n),rd(m);
    int x,y,z;
    inc(i,1,n)inc(j,1,n)d[i][j]=inf;
    inc(i,1,m)
    {
        rd(x),rd(y),rd(z);
        d[x][y]=d[y][x]=min(d[x][y],z);
    }
    
    vis[1]=1;
    inc(i,2,n)dis[i]=d[1][i];
    
    int ans=0,cnt=n-1;
    while(cnt--)
    {
        int now,minn=inf;
        inc(i,1,n)
        if(!vis[i]&&dis[i]<minn)minn=dis[i],now=i;
        
        vis[now]=1;
        ans+=dis[now];
        
        inc(i,1,n)dis[i]=min(dis[i],d[now][i]);
    }
    printf("%d",ans);
    re 0;
}
View Code

2.最短路

已经凉透了的spfa

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=1e4+5,maxm=5e5+5;
int n,m,hd[maxn];
struct node{
    int to,nt,val;
}e[maxm<<1];
int k,s;
inline void add(int x,int y,int z){
    e[++k]=(node){y,hd[x],z};hd[x]=k;
}

#define ll long long
ll inf=2147483647,dis[maxn],vis[maxn];
inline void spfa()
{
    inc(i,1,n)dis[i]=inf;
    dis[s]=0;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=hd[x];i;i=e[i].nt)
        {
            int v=e[i].to;
            if(dis[v]>dis[x]+e[i].val)
            {
                dis[v]=dis[x]+e[i].val;
                if(!vis[v])
                {
                    vis[v]=1;
                        q.push(v);    
                }
            }
        }
    }
}

int main()
{
    freopen("a.in","r",stdin);
    rd(n),rd(m),rd(s);
    int x,y,z;
    inc(i,1,m)
    {
        rd(x),rd(y),rd(z);
        add(x,y,z);
    }
    
    spfa();
    
    inc(i,1,n)printf("%lld ",dis[i]);
    re 0;
}
View Code

 

非常好看且实用的dijkstra

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=1e4+5,maxm=5e5+5;
int n,m,hd[maxn];
struct node{
    int to,nt,val;
}e[maxm<<1];
int k,s;
inline void add(int x,int y,int z){
    e[++k]=(node){y,hd[x],z};hd[x]=k;
}

#define ll long long
ll inf=2147483647,dis[maxn];
struct KKK{
int x,val;
inline bool operator<(KKK u)const 
{
    re val>u.val;
}
};
inline void dij()
{
    inc(i,1,n)dis[i]=inf;
    dis[s]=0;
    priority_queue<KKK>q;
    q.push((KKK){s,0});
    while(!q.empty())
    {
        KKK u=q.top();
        q.pop();
        int x=u.x;
        if(dis[x]!=u.val)continue;
        for(int i=hd[x];i;i=e[i].nt)
        {
            int v=e[i].to;
            if(dis[v]>dis[x]+e[i].val)
            {
                dis[v]=dis[x]+e[i].val;
                q.push((KKK){v,dis[v]});
            }
        }
    }
}

int main()
{
    freopen("a.in","r",stdin);
    rd(n),rd(m),rd(s);
    int x,y,z;
    inc(i,1,m)
    {
        rd(x),rd(y),rd(z);
        add(x,y,z);
    }
    
    dij();
    
    inc(i,1,n)printf("%lld ",dis[i]);
    re 0;
}
View Code

 

玄学暴力的floyd

    inc(k,1,n)
    inc(i,1,n)
    inc(j,1,n)
    d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
View Code

3.树的直径

不好找路径的树形DP

inline void dfs(int x,int fa)
{

    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to,w=e[i].val;
        if(v==fa)continue;
        dfs(v,x);
        if(d0[v]+w>d2[x])
        {
            d2[x]=d0[v]+w;
            if(d2[x]>d1[x])
            {
                swap(d2[x],d1[x]);
                if(d1[x]>d0[x])
                swap(d0[x],d1[x]);
            }
        }
    }
    ans=max(ans,d0[x]+d1[x]);
}
inline void dfs2(int x,int fa)
{
    ans=max(ans,g[x]+d0[x]);
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v==fa)continue;
        g[v]=g[x]+e[i].val;
        dfs2(v,x);
    }
}
View Code

 

弄不好负权的两次dfs

inline void dfs(int x,int fa)
{
    if(dis[x]>maxx)maxx=dis[x],p=x;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v=fa)continue;
        dis[v]=dis[x]+e[i].val;
        dfs(v,x);
    }
}
View Code

4.树的最近公共祖先

1.倍增

inline void dfs(int x)
{
    for(int i=1;fa[fa[x][i-1]][i-1];++i)
    fa[x][i]=fa[fa[x][i-1]][i-1];
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v==fa[x][0])continue;
        fa[v][0]=x;
        deep[v]=deep[x]+1;
        dfs(v);
    }
}

inline int LCA(int x,int y)
{
    if(deep[x]<deep[y])swap(x,y);
    
    dec(i,20,0)
    if(deep[fa[x][i]]>=deep[y])
    {
        x=fa[x][i];
    }
    
    if(x==y)re x;
    dec(i,20,0)
    if(fa[y][i]!=fa[x][i])
    {
        x=fa[x][i];
        y=fa[y][i];
    }
    re fa[x][0];
}
View Code

 

2.树链剖分

inline void dfs1(int x,int fa)
{
    siz[x]=1;
    deep[x]=deep[fa]+1;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v==fa)continue;
        dfs1(v,x);
        siz[x]+=siz[v];
        if(siz[v]>siz[son[x]])son[x]=v;
    }
}

inline void dfs2(int x,int fp)
{
    top[x]=fp;
    rev[seg[x]=++tot]=x;
    if(son[x])
    {
        dfs2(v,fp);
        bot[x]=bot[son[x]];
        for(int i=hd[x];i;i=e[i].nt)
        {
            int v=e[i].to;
            if(!top[v])dfs2(v,v);
        }
    }
    else bot[x]=x;
}

inline void LCA(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y])swap(x,y);
    re x;
}
View Code

 

3.tarjan

+并查集

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=5e5+5;
int n,m,s;
int hd[maxn],hd1[maxn];
struct node{
    int to,nt;
}e[maxn<<1];
struct nide{
    int q1,ans,id,nt;
    inline bool operator<(nide b)const{
    re id<b.id;}
}q[maxn];
int k,k1=1;
inline void add(int x,int y){e[++k]=(node){y,hd[x]};hd[x]=k;}
inline void addq(int x,int y){q[++k1]=(nide){y,0,k1,hd1[x]};hd1[x]=k1;}

int vis[maxn],fa[maxn];
inline int find(int x){re x==fa[x]?x:fa[x]=find(fa[x]);}

inline void dfs(int x,int pre)
{
    vis[x]=1;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v==pre)continue;
        dfs(v,x);
        fa[v]=x; 
    }
    
    for(int i=hd1[x];i;i=q[i].nt)
    {
        int v=q[i].q1;
        if(!vis[v]||q[i].ans)continue;
        else q[i].ans=q[i^1].ans=find(v);
    }
}

int main()
{
    freopen("a.in","r",stdin);
    rd(n);rd(m);rd(s);
    int x,y;
    inc(i,1,n)fa[i]=i;
    inc(i,2,n)
    {
        rd(x),rd(y);
        add(x,y);add(y,x);
    }
    inc(i,1,m)
    {
        rd(x),rd(y);
        addq(x,y),addq(y,x);
    }
    dfs(s,0); 
    sort(q+1,q+k1+1);
    for(int i=2;i<=k1;i+=2)
    {
        printf("%d\n",q[i].ans);
    } 
    re 0;
}
View Code

5.树上差分

点的差分:cnt(s)++,cnt(t)++,cnt(lca)--,cnt(falca)--;

边的差分:cnt(s)++,cnt(t)++,cnt(lca)-2;【cnt代表其父到他的路径】

然后跑一边dfs遍历全树

6.差分约束

7.tarjan系列大礼包       

1.割点(对于无向图G,删除节点x以及与x相连的边,会分裂两个图的节点x)

if(low[v]>=dfn[x])
{
        ++siz;
        if(rt!=x||siz>1)g[x]=1;
}    
#include<bits/stdc++.h> 
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=2e4+4,maxm=1e5+5;
int n,m,hd[maxn],g[maxn];
struct node{
    int to,nt;
}e[maxm<<1];
int k=1;
inline void add(int x,int y){
    e[++k]=(node){y,hd[x]};hd[x]=k;
}

int dfn[maxn],low[maxn],tot,rt;
inline void tarjan(int x,int E)
{
    dfn[x]=low[x]=++tot;
    int siz=0;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(i==(E^1))continue;
        if(!dfn[v])
        {
            tarjan(v,i);
            low[x]=min(low[x],low[v]);
            if(low[v]>=dfn[x])
            {
                ++siz;
                if(rt!=x||siz>1)g[x]=1;
            }
        }
        else low[x]=min(low[x],dfn[v]);
    }
}

int main()
{
    freopen("a.in","r",stdin);
    rd(n),rd(m);
    int x,y;
    inc(i,1,m)
    {
        rd(x),rd(y);
        add(x,y);
        add(y,x);
    }
    
    inc(i,1,n)
    if(!dfn[i])rt=i,tarjan(i,0);
    
    
    int cnt=0;
    inc(i,1,n)if(g[i])++cnt;
    printf("%d\n",cnt);
    inc(i,1,n)
    if(g[i])printf("%d ",i);
    re 0;
}
View Code

 

2.桥(对于无向图G,删除边E,会变成两个图的边E)

if(i==(E^1))continue;
if(low[v]>dfn[x])bridge[i]=beidge[i^1]=1;
inline void tarjan(int x,int E)
{
    dfn[x]=low[x]=++tot;
    int siz=0;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(i==(E^1))continue;
        if(!dfn[v])
        {
            tarjan(v,x);
            if(low[v]>dfn[x])
            bridge[i]=beidge[i^1]=1;
        }
        else low[x]=min(low[x],dfn[v]);
    }
}
View Code

 

3.点双(由孤立节点和其他点双连通分量组成)

!!!割点可能属于多个v_dcc,但其他的点只属于一个

!!!顺便求出割点(缩点有用)

求取

#include<bits/stdc++.h> 
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

int rt,dfn[maxn],low[maxn],tot,s[maxn],stop;
vector<int>v_dcc[maxn],v_cnt;
inline void tarjan(int x)
{
    dfn[x]=low[x]=++tot;
    s[++stop]=x;
    if(rt==x&&!hd[x])//孤立点
    {
        v_dcc[++v_cnt].push_back(x);
        --stop;
        re ;
    } 
    int siz=0;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(!dfn[v])
        {
            tarjan(v);
            low[x]=min(low[x],low[v]);
            if(low[v]>=dfn[x])
            {
                ++siz;
                if(rt!=x||siz>1)cut[x]=1;
                ++v_cnt;
                while(s[stop+1]==v)//!!!!!!!!只能判v,因为y之前,x之后可能还有其他节点 
                {
                    v_dcc[v_cnt].push_back(s[stop]);
                    --stop;
                }
                v_dcc[v_cnt].push_back(x);
            }
        }
        else low[x]=min(low[x],dfn[v]); 
    }
}

int main()
{
    //……
     inc(i,1,n)
         if(!dfn[i])rt=x,tarjan(i);
}
View Code

缩点

给每个割点一个新的编号

建新图,从每个v_dcc到它包含的所有的割点连边

 (在求取的基础代码的main函数中加入)

int main()
{
    inc(i,1,n)if(!dfn[i])tarjan(i);
    int num=v_cnt; 
    inc(i,1,n)if(cut[i])new_id[i]=++num;
    inc(i,1,v_cnt)
    inc(vector<int>::iterator it=v_dcc[i].begin();it!=v_dcc[i].end();++it){
        int v=*it;
        if(cut[v])
        {
            add(i,new_id[v]);
            add(new_id[v],i);
        }
    }
    re 0;
}
View Code

 

4.边双

求取:删除所有桥的情况下,得到的所有连通块

可以用一个dfs

inline void dfs(int x)
{
    c[x]=e_dcc
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(c[v]||bridge[i])continue;
        dfs(v);
    }
}
int main()
{
    //…… 
    tarjan();
    inc(i,1,n)
    if(!c[i]) 
    {
        ++e_dcc;
        dfs(i);
    }
    re 0;
}
View Code

 

缩点:求取边双的情况下得到各个点所属的边双

if(c[x]==c[y])continue;
else add(c[x],c[y])

也就是说新图的边就只剩下桥

重新建图就好

 

5.强连通

 

inline void tarjan(int x)
{
    dfn[x]=low[x]=++tot;
    s[++stop]=x;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(!dfn[v]){
            tarjan(v);
            low[x]=min(low[x],low[v]);
        }
        else if(!belong[v])low[x]=min(low[x],dfn[v]);
    }
    if(dfn[x]==low[x])
    {
        ++col;
        while(s[stop+1]!=x)
        {
            belong[s[stop]]=col;
            --stop;
        }
    }
}
View Code

 

6. 2-sat

8.判负环

在保证有负环的情况下用基于dfs的spfa可能要比基于bfs的spfa要快一点

然而,我不会

暴力选手LL泪流满面

只能跑n遍spfa

9.基环树

我做过的大概就是两个思路

当然是针对环处理的

首先找出环

1.转成环形dp

2.强制断开某条边

代码什么的都太烦了

提供三个找环的方向

a.toposort 可以在预先将非环点处理同时 通过未访问过的点得到环

b.dfs爆搜,遇到访问过的点逆回(因为基环树只可能有一个环)

c.使用并查集,然而不幸的是你只能得到每个环上的一双点与一条边

10.二分图

奇环

inline bool dfs(int x,int col)
{
    c[x]=col;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(c[v]==col)re 1;
        else if(c[v]==-1)dfs(v,col^1);
    }
}

int main()
{
    memset(c,-1,sizeof c);
    //找奇环 
    inc(i,1,n)
    {
        if(!c[i])dfs(c[i]);
        //存在奇环
        //且包括包括奇环的环也可分为奇环
        //实用于判断有无奇环
        //以及tarajan 
    }
    
    re 0;
}
View Code

最大匹配

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x; 
}
const int maxn=1005;
int n,m,hd[maxn],belong[maxn],vis[maxn];
struct node{
    int to,nt;
}e[maxn*maxn];
int k;
inline void add(int x,int y)
{
    e[++k]=(node){y,hd[x]};hd[x]=k;
}

inline bool vivi(int x)
{
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(!vis[v])
        {
            vis[v]=1;
            if(!belong[v]||vivi(belong[v]))
            {
                belong[v]=x;
                re 1;
            }
        }
    }
    re 0;
} 

int main()
{
    freopen("a.in","r",stdin);
    int E,x,y;
    rd(n),rd(m),rd(E) ;
    inc(i,1,E)
    {
        rd(x),rd(y);
        if(x>n||y>m)continue;
        add(x,y);
    }
    
    int ans=0;
    inc(i,1,n)
    {
        memset(vis,0,sizeof vis);
        ans+=vivi(i);
    }
    
    printf("%d",ans);
}
View Code

呃,最大权值匹配KM算法就弄费用流吧

KM不常用,还有局限性,最主要是我背不到

背不到就是背不到,就算差不多我将高中语文必背都背完了,也背不到

还是放个板子

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define re return
#define ll long long
#define inc(i,l,r) for(int i=l;i<=r;++i)

const int inf=2147483647,maxn=305;
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

int n;
int ex1[maxn];//1的期望度
int ex2[maxn];//2的期望度
int pri[maxn][maxn];//价格
int match[maxn];//匹配2的1
int vis1[maxn];//1是否被访问过
int vis2[maxn];//2是否访问过
int slack[maxn];//最小差多少,2可以被1访问

inline bool dfs(int x)
{
    vis1[x]=1;//标记1访问
    inc(i,1,n)
    {
        if(vis2[i])continue;
        if(ex1[x]+ex2[i]==pri[x][i])//达到访问要求
        {
            vis2[i]=1;标记2访问
            if(!match[i]||dfs(match[i]))
            {
                match[i]=x;
                re 1;
            }
        }
        else slack[i]=min(slack[i],ex1[x]+ex2[i]-pri[x][i]);
//2差值统计
    }
    re 0;
}

inline void KM()
{
    inc(i,1,n)match[i]=ex2[i]=0;
//刷新
    inc(i,1,n)
    {
        inc(j,1,n)
        slack[j]=inf;
        while(2333)
        {
            inc(j,1,n)vis1[j]=vis2[j]=0;
            if(dfs(i))break;
            int d=inf;
            inc(j,1,n)
            if(!vis2[j])
                d=min(d,slack[j]); 
//最小改变度
            inc(j,1,n)
            {
                if(vis1[j])ex1[j]-=d;
                if(vis2[j])ex2[j]+=d;
                else slack[j]-=d;
//分别改变
            }
        }
    }
}

int main()
{
    while(~scanf("%d",&n))
    {
        
        inc(i,1,n)ex1[i]=-inf;
        inc(i,1,n)    
        inc(j,1,n)
        {
            rd(pri[i][j]);
            ex1[i]=max(ex1[i],pri[i][j]);
        }
        int ans=0;
        KM();
        for(int i=1;i<=n;++i)
        ans+=pri[match[i]][i];
        printf("%d\n",ans);
    }

    
    re 0;
}
View Code

最小点覆盖=最大匹配

最大独立集=节点总数-最小点覆盖=节点总数-最大匹配

 

有向无环图的最小点覆盖

11.欧拉回路

12.网络流

定理:最大流=最小割

最大流

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}
const int maxn=1e4+4,maxm=1e5+5; 
int n,m,hd[maxn],s,t;
struct node{
    int to,nt,w;
}e[maxm<<1];
int k=1;
inline void add(int x,int y,int z)
{
    e[++k]=(node){y,hd[x],z};hd[x]=k;
    e[++k]=(node){x,hd[y],0};hd[y]=k;
}

int deep[maxn],cur[maxn];
inline bool bfs()
{
    inc(i,1,n)deep[i]=0;
    deep[s]=1;
    queue<int>q;
    q.push(s);
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        for(int i=hd[x];i;i=e[i].nt)
        {
            int v=e[i].to;
            if(!deep[v]&&e[i].w)
            {
                deep[v]=deep[x]+1;
                if(v==t)re 1;
                q.push(v);
            }
        }
    }
    re 0;
}

inline int dfs(int x,int flow)
{
    if(x==t)re flow;
    int delta=flow;
    for(int &i=cur[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(deep[v]==deep[x]+1&&e[i].w)
        {
            int d=dfs(v,min(e[i].w,delta));
            e[i].w-=d;e[i^1].w+=d;
            delta-=d;
            if(!delta)re flow;
        }
    }
    re flow-delta;
}
int main()
{
    //freopen("a.in","r",stdin);
    rd(n),rd(m),rd(s),rd(t);
    int x,y,w;
    inc(i,1,m)
    {
        rd(x),rd(y),rd(w);
        add(x,y,w);
    }
    
    int ans=0;
    while(bfs())
    {
        inc(i,1,n)cur[i]=hd[i];
        ans+=dfs(s,2147483647);
    }
    printf("%d",ans);
    re 0;
}
View Code

费用流

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}
const int maxn=5e3+3;

int k=1,n,m,s,t;
int dis[maxn],ord[maxn],hd[maxn],flow[maxn],vis[maxn];
int smoney,sflow;

struct node{
    int flow,to,nt,cost;
}e[100005];
inline void add(int u,int v,int w,int f)
{
    e[++k].to=v;e[k].nt=hd[u];e[k].flow=w;e[k].cost=f;hd[u]=k;
}

inline bool spfa()
{
    queue<int>q;
    memset(dis,0x3f3f3f3f,sizeof dis);
    memset(vis,0,sizeof vis);
    q.push(s);
    dis[s]=0;
    flow[s]=0x3f3f3f3f;
    while(!q.empty())
    {
        int x=q.front();
        q.pop();
        vis[x]=0;
        for(int i=hd[x];i;i=e[i].nt)
        {
            int v=e[i].to,w=e[i].flow,f=e[i].cost;
            if(w&&dis[v]>dis[x]+f)
            {
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
                flow[v]=min(flow[x],w);
                dis[v]=dis[x]+f;
                ord[v]=i;
            }
        }
    }
    re dis[t]!=0x3f3f3f3f;
}

inline void vivi()
{
    int x=t;
    while(x!=s)
    {
        int i=ord[x];
        e[i].flow-=flow[t];
        e[i^1].flow+=flow[t];
        x=e[i^1].to;
    }
    sflow+=flow[t];
    smoney+=flow[t]*dis[t];
}
int main()
{
    freopen("a.in","r",stdin);
    rd(n),rd(m),rd(s),rd(t);
    int u,v,w,f;
    inc(i,1,m)
    {
        rd(u),rd(v),rd(w),rd(f);
        add(u,v,w,f);
        add(v,u,0,-f);
    }
    while(spfa())
        vivi();
    printf("%d %d",sflow,smoney);
    re 0;
}
View Code

 

 

三.高精度

四.数学

1.线性筛素数

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}
const int maxn=1e7+5;
int n,m,notprime[maxn],prime[maxn],p_cnt;

inline void Get_prime()
{
    notprime[1]=1;
    inc(i,2,n)
    {
        if(!notprime[i])prime[++p_cnt]=i;
        
        inc(j,1,p_cnt)
        {
            if(prime[j]*i>n)break;
            notprime[i*prime[j]]=1;
            if(i%prime[j]==0)break;
        }
    }
}

int main()
{
    freopen("a.in","r",stdin);
    rd(n),rd(m);
    Get_prime();
    int x;
    inc(i,1,m)
    {
        rd(x);
        if(notprime[x])puts("No");
        else puts("Yes");
    }
    re 0;
}
View Code

2.欧几里得

inline int gcd(int a,int b){re b?gcd(b,a%b):a;}

3.扩展欧几里得

inline int exgcd(int a,int b,int &x,int &y)
{
    if(!b){x=1,y=0;re a;}
    int d=exgcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    re d;
}

int main()
{
    //a*x+b*y=c;
    int a,b,x,y,c=1;
    rd(a),rd(b);
    int d=exgcd(a,b,x,y);
    if(c%d)printf("-1");
    else x=x*c/d;
    //最小正整数
    x=(x%b+b)%b;
    printf("%d",x);
    re 0;
}

 

4.欧拉函数

单求

线性筛

5.欧拉定理

6.逆元

单求

费马小定理:如p是质数,且Gcd(a,p)=1,那么 a^(p-1) ≡1(mod p)

即a的逆元=>a^(p-2)

线性筛

    inv[1]=1;
    inc(i,2,n)inv[i]=1ll*(P-P/i)*inv[P%i]%P;
    inc(i,1,n)printf("%d\n",inv[i]);

 

7.中国剩余定理

 

8.矩阵

 

9.高斯消元

 

10线性基

 

11.组合数

性质:

 

 

 

 2^n=(n 0)+(n 1)+(n 2)+……+(n n)

 

二项式定理

 

 

Lucas定理

 

 

ll jc[100005],p;

inline ll pow(ll a,ll x)
{
    ll ret=1;
    while(x)
    {
        if(x&1)ret=ret*a%p;
        a=a*a%p;
        x>>=1;
    }
    re ret;
}

inline ll C(ll n,ll m)
{
    if(m>n)re 0;
    re jc[n]*pow(jc[m],p-2)%p*pow(jc[n-m],p-2);
}

inline ll LUCAS(ll n,ll m)
{
    if(!m)re 1;
    re C(n%p,m%p)*LUCAS(n/p,m/p)%p;
}

int main()
{
    //freopen("in.txt","r",stdin);
    int T;
    rd(T);
    while(T--)
    {
        jc[0]=1;
        ll n,m;
        rd(n),rd(m),rd(p);
        inc(i,1,p)jc[i]=jc[i-1]*i%p;
        printf("%lld\n",LUCAS(n+m,m));
    }

    re 0;
} 

catalan数

n个0与n个1构成的序列方案数,使得任何一个前缀0的个数不少于1的个数

对于在n位的2进制中,有m个0,其余为1的catalan数为:C(n,m)-C(n,m-1)

12.0/1分数规划

 

13.博弈论

 

posted @ 2019-11-14 11:52  凉如水  阅读(207)  评论(0编辑  收藏  举报