zoukankan      html  css  js  c++  java
  • 2020牛客暑期多校训练营(第一场)

    J.Easy Integration

    公式题,沃利斯积分:(int_{0}^{1}{(x-x^2)^n}dx=frac{(n!)^2}{(2n+1)!})
    一直按照分部积分公式:(int{u(x)v'(x)dx}=u(x)v(x)-int{u'(x)v(x)dx})
    推导:
    (int_{0}^{1}{(x-x^2)^n}dx)
    (=frac{1}{n+1}int_{0}^{1}{[x^{n+1}]' (1-x)^n dx})
    (=frac{1}{n+1}(x^{n+1}(1-x)^n|_0^1-int_{0}^{1}{x^{n+1}[(1-x)^n]'}dx))
    (=frac{n}{n+1}int_{0}^{1}{x^{n+1}(1-x)^{n-1}}dx)
    以此类推,可得:
    (frac{n*(n-1)*...*1*int_{0}^{1}{x^{2n}}}{(n+1)*(n+2)*...*(2n)})
    (=frac{n!}{(n+1)*...*(2n+1)})
    (=frac{(n!)^2}{(2n+1)!})

    代码:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const ll mod=998244353;
    const int N=1e6+6;
    const int maxn=2e6+1;
    ll f[N<<1],inv[N<<1];
    ll power(ll a,ll b)
    {
        ll res=1;
        while(b)
        {
            if(b&1) res=res*a%mod;
            a=a*a%mod;
            b>>=1;
        }
        return res;
    }
    void init()
    {
        f[0]=1;//阶乘
        for(int i=1;i<=maxn;i++)
            f[i]=f[i-1]*i%mod;
        for(int i=0;i<=maxn;i++)//1!~(2n+1)!逆元
            inv[i]=power(f[i],mod-2);
    }
    int main()
    {
        init();
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            ll ans=f[n]*f[n]%mod*inv[2*n+1]%mod;
            printf("%lld
    ",ans);
        }
        return 0;
    }
    
    

    I.1 or 2

    解1:

    拆点,求最大匹配。

    但这样写,应该有问题的。不能保证上次从点 (u) 取了和 (v) 之间的边,下次从 (v) 就会取和 (u) 之间的边。
    比如下面的图就就有问题

    应该输出 (No),但输出了 (Yes)

    代码1:

    #include<bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N=110;
    const int inf=0x3f3f3f3f;
    struct node
    {
        int to,val,rev;//边的终点,边的容量,方向边的索引
    };
    vector<node>pic[N<<1];
    queue<int>que;
    int layer[N<<1],iter[N<<1];//iter[]数组用于当前弧优化
    int vn,s,t;
    bool bfs()
    {
        for(int i=0;i<=vn;i++)
            layer[i]=-1;
        while(!que.empty())
            que.pop();
        layer[s]=0;
        que.push(s);
        while(!que.empty())
        {
            int a=que.front();
            que.pop();
            for(int i=0;i<pic[a].size();i++)
            {
                node b=pic[a][i];
                if(layer[b.to]<0&&b.val>0)//layer[]相对于标记
                {
                    layer[b.to]=layer[a]+1;
                    que.push(b.to);
                    if(b.to==t)//不用把所有的点都分层,只要分到汇点就行
                        return true;
                }
            }
        }
        return false;
    }
    int dfs(int a,int c)//
    {
        if(a==t)
            return c;
        for(int &i=iter[a];i<pic[a].size();i++)//当前弧优化,已经用过非边不再遍历,引用
        {
            node &e=pic[a][i];//引用,后面可以直接修改数据
            if(e.val>0&&layer[e.to]>layer[a])//只走后面的层次的点
            {
                int d=dfs(e.to,min(c,e.val));//每次找到一条增广路后,一直回溯到起点,并在此过程中确定路上的最小流量
                if(d>0)
                {
                    e.val-=d;
                    pic[e.to][e.rev].val+=d;//改变时要对原来的信息修改
                    return d;//返回该条增广路的最大流
                }
            }
        }
        return 0;//
    }
    int dinic()
    {
        int max_flow=0;
        while(bfs())
        {
            int f=0;
            memset(iter,0,sizeof(iter));
            while((f=dfs(s,inf))>0)
                max_flow+=f;
        }
        return max_flow;
        //printf("%d
    ",max_flow);
    }
    void add(int u,int v,int w)
    {
        pic[u].pb({v,w,pic[v].size()});
        pic[v].pb({u,0,pic[u].size()-1});
    }
    int main()
    {
        int n,m;
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            int d=0,tol=0;
            vn=2*n+1;
            s=0,t=vn;
            for(int i=0;i<=vn;i++)
                pic[i].clear();
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&d);
                tol+=d;
                add(0,i,d);
                add(i+n,vn,d);
            }
            int u,v;
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&u,&v);
                add(u,v+n,1);
                add(v,u+n,1);
            }
            int ans=dinic();//cout<<"ans="<<ans<<endl;cout<<"tol="<<tol<<endl;
            if(ans==tol) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
    
    
    

    代码2:

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    typedef pair<int,int>pii;
    const int N=55;
    int d[N],a[N];
    vector<pii>pic[N];
    bool vis[N<<1];
    int n,m;
    bool cmp(int x,int y)
    {
        return pic[x].size()<pic[y].size();
    }
    bool dfs(int k)
    {
        if(k>n) return 1;
        if(d[a[k]]==0) return dfs(k+1);//该电的度已满足,找下一个点
        for(int i=0;i<pic[a[k]].size();i++)
        {
            int u=pic[a[k]][i].first;
            int e=pic[a[k]][i].second;
            if(vis[e]||d[u]==0) continue;//边走过或者该点的度已经满足
            d[a[k]]--,d[u]--,vis[e]=1;
            bool f=dfs(k);
            if(f) return 1;
            vis[e]=0,d[a[k]]++,d[u]++;
        }
        return 0;
    }
    int main()
    {
        while(scanf("%d%d",&n,&m)!=EOF)
        {
            memset(vis,false,sizeof(vis));
            for(int i=1;i<=n;i++)
            {
                scanf("%d",&d[i]);
                a[i]=i;
                pic[i].clear();
            }
            int u,v;
            for(int i=1;i<=m;i++)
            {
                scanf("%d%d",&u,&v);
                pic[u].pb(make_pair(v,i));
                pic[v].pb(make_pair(u,i));
            }
            sort(a+1,a+1+n,cmp);//把点按度排序
            if(dfs(1)) printf("Yes
    ");
            else printf("No
    ");
        }
        return 0;
    }
    
    

    H.Minimum-cost Flow

    https://www.cnblogs.com/1024-xzx/p/13300229.html

  • 相关阅读:
    linux如何添加内核模块
    LINUX内核符号表
    MIPS 架构
    将char转成bit,文件读写
    回顾一下今天VIM历程,加深印象,以免忘记!
    Notebook of A Road Map Through Nachos
    老林课上笔记
    C# 通过探测邮件服务器进行Email地址有效性检验
    详解在visual studio中使用git版本系统(图文)
    基于aspnet Forms身份验证基本原理
  • 原文地址:https://www.cnblogs.com/1024-xzx/p/13289912.html
Copyright © 2011-2022 走看看