[自用模板]持续更新!

组合数学:

一篇讲逆元的很不错的博客:http://blog.youkuaiyun.com/acdreamers/article/details/8220787

求很大组合数(逆元加快速幂)

typedef long long LL;
const int MOD = 1e9+7;
const int MAXN = 1e6+10;
LL inv[MAXN];
void inverse(){
    inv[1]=1;
    for(int i=2;i<MAXN;i++){
        inv[i]=(MOD-MOD/i)*inv[MOD%i]%MOD;
    }
}
LL Cm[MAXN],Ck[MAXN];
LL _pow(LL a,int n){
    if(n==0) return 1;
    LL sum=_pow(a,n/2);
    sum=sum*sum%MOD;
    if(n&1) sum=sum*a%MOD;
    return sum;
}
int n,m,k;
void get_C(){
    Ck[0]=Cm[0]=1;
        for(int i=1;i<=k;i++){
            Cm[i]=Cm[i-1]%MOD*(m-i+1)%MOD*inv[i]%MOD;
            Ck[i]=Ck[i-1]%MOD*(k-i+1)%MOD*inv[i]%MOD;
        }
}


图论:

单源最短路径spfa两种写法(dfs和bfs)

int spfa_bfs(int s)
{
    queue <int> q;
    memset(d,0x3f,sizeof(d));
    d[s]=0;
    memset(c,0,sizeof(c));
    memset(vis,0,sizeof(vis));

    q.push(s);  vis[s]=1; c[s]=1;
    //顶点入队vis要做标记,另外要统计顶点的入队次数
    int OK=1;
    while(!q.empty())
    {
        int x;
        x=q.front(); q.pop();  vis[x]=0;
        //队头元素出队,并且消除标记
        for(int k=f[x]; k!=0; k=nnext[k]) //遍历顶点x的邻接表
        {
            int y=v[k];
            if( d[x]+w[k] < d[y])
            {
                d[y]=d[x]+w[k];  //松弛
                if(!vis[y])  //顶点y不在队内
                {
                    vis[y]=1;    //标记
                    c[y]++;      //统计次数
                    q.push(y);   //入队
                    if(c[y]>NN)  //超过入队次数上限,说明有负环
                        return OK=0;
                }
            }
        }
    }

    return OK;

}

int spfa_dfs(int u)
{
    vis[u]=1;
    for(int k=f[u]; k!=0; k=e[k].next)
    {
        int v=e[k].v,w=e[k].w;
        if( d[u]+w < d[v] )
        {
            d[v]=d[u]+w;
            if(!vis[v])
            {
                if(spfa_dfs(v))
                    return 1;
            }
            else
                return 1;
        }
    }
    vis[u]=0;
    return 0;
}

网络流

求最大流的Edmonds-Karp算法(bfs实现)

const int maxn = 50 + 5;
const int INF = 0x7f7f7f7f;
struct Edge{
    int from,to,cap,flow;
    Edge(int u=0,int v=0 ,int c=0,int f=0): from(u),to(v),cap(c),flow(f){}
};
struct EdmondsKarp{
    int n,m;
    vector<Edge> edges;
    vector<int> G[maxn];
    int a[maxn];
    int p[maxn];

    void Init(int n){
        for(int i=0;i<n;i++) G[i].clear();
        edges.clear();
    }

    void AddEdge(int from,int to,int cap){
        edges.push_back(Edge(from,to,cap,0));
        edges.push_back(Edge(to,from,0,0));
        m=edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    int MaxFlow(int s,int t){
        int flow=0;
        for(;;){
            memset(a,0,sizeof(a));
            queue<int> Q;
            Q.push(s);
            a[s]=INF;
            while(!Q.empty()){
                int x=Q.front(); Q.pop();
                for(int i=0;i<G[x].size();i++){
                    Edge& e=edges[G[x][i]];
                    if(!a[e.to]&&e.cap>e.flow){
                        a[e.to]=min(a[x],e.cap-e.flow);
                        p[e.to]=G[x][i];
                        Q.push(e.to);
                    }
                }
                if(a[t]) break;
            }
            if(!a[t]) break;
            for(int u=t;u!=s;u=edges[ p[u] ].from){
                edges[ p[u] ].flow+=a[t];
                edges[ p[u]^1 ].flow -= a[t];
            }
            flow += a[t];
        }
        return flow;
    }
};
EdmondsKarp g;


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值