zoukankan      html  css  js  c++  java
  • [???]天上红绯

    题目描述 Description
    天上红绯在游戏中扮演敏剑,对于⾼攻击低防御的职业来说,爆发⼒显得⾮常重要,为此,她准备学习n个技能,每个技能都有2个学习⽅向:物理攻击和魔法攻击。对于第i个技能,如果选择物理攻击⽅向,会增加ap_i的爆发⼒,如果选择魔法攻击的⽅向,会增加ad_i的爆发⼒。此外,还有⼀些combo,⼀个combo由两个技能组成,对于第i个combo,如果他们都是魔法攻击,会额外增加AD_i的爆发⼒,如果他们都是物理攻击,会额外增加AP_i的爆发⼒,如果他们不属于同⼀类型,会减少AX_i的爆发⼒。她找到了你,请你帮她选择技能的类型,产⽣最⼤的爆发⼒
    输入描述 Input Description

    第⼀⾏2个正整数n,m,表⽰技能的个数和combo的个数接下来n⾏每⾏2个正整数,描述⼀个技能的ap_i,ad_i接下来m⾏每⾏5个正整数u,v,AD_i,AP_i,AX_i,描述⼀个combo,表⽰技能u和技能v产⽣combo

    输出描述 Output Description
    ⼀⾏,⼀个整数,表⽰最⼤的爆发⼒
    样例输入 Sample Input
    2 1
    50 5
    10 20
    1 2 100 50 50
    样例输出 Sample Output
    125
    数据范围及提示 Data Size & Hint
    测试点编号
       n      m
    1  5      5
    2  50     100
    3  100000 0
    4  500000 0
    5  1000   3000
    6  1000   3000
    7  1000   3000
    8  10000  40000
    9  10000  40000
    10 10000  40000

    对于所有的测试点,确保不会爆long long

     根据套路,这是一道最小割的题,至于建图,依据经验,我们很容易想到对于每一个点i,s向i连一条物理攻击的边,i向t连一条魔法攻击的边,这肯定是没有问题的。之后我们考虑combo问题,回顾一下题意:如果他们都是魔法攻击,会额外增加AD_i的爆发⼒,如果他们都是物理攻击,会额外增加AP_i的爆发⼒,如果他们不属于同⼀类型,会减少AX_i的爆发⼒。首先肯定能想到comboi一定要与ui与vi有联系。考虑本题中割的意思,对于一个点i,割物理攻击的边表示i要使用魔法攻击,割魔法攻击的边表示i要使用物理攻击,而割的目的是为了使s与t不联通,砍掉一条通路才可以。对于一个combo,只有两个技能都用物理了才能启用APi的输出,于是我们尝试ui,vi分别向combo点连一条Api的双向边,combo再向t连一条APi的边。这样就能很好的解决问题。对于魔法攻击类似,所以对于每一个combo要开两个点。剩下AXi的关系那就很显然是ui与vi连一条双向边了,容量为AXi.

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<queue>
    using namespace std;
    typedef long long LL;
    #define mem(a,b) memset(a,b,sizeof(a))
    inline LL read()
    {
        LL x=0,f=1;char c=getchar();
        while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
        while(isdigit(c)){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    const int maxn=500010,maxm=40010;
    const LL oo=999999999;
    LL ad[maxn],ap[maxn],AD[maxm],AP[maxm],AX[maxm];
    int n,m,u[maxn],v[maxn]; 
    const int maxN=90010,maxM=400010;
    struct Edge
    {
        int u,v,next;LL f;
        Edge() {}
        Edge(int _1,int _2,LL _3,int _4): u(_1),v(_2),f(_3),next(_4) {}
    }e[2*maxM];
    struct Dinic
    {
        int first[maxN],dis[maxN],cur[maxN],a,b,c,ce,N,s,t;
        bool vis[maxN];queue <int> Q;
        void addEdge(int a,int b,LL c)
        {
            e[++ce]=Edge(a,b,c,first[a]);first[a]=ce;
            e[++ce]=Edge(b,a,0,first[b]);first[b]=ce; 
        }
        void init_build()
        {
            mem(first,-1);ce=-1;
            s=n+2*m+1;t=n+2*m+2;
            for(int i=1;i<=n;i++)addEdge(s,i,ad[i]),addEdge(i,t,ap[i]);
            for(int i=1;i<=m;i++)
            {
                addEdge(s,n+2*i-1,AD[i]);addEdge(n+2*i,t,AP[i]);
                addEdge(u[i],v[i],AX[i]);addEdge(v[i],u[i],AX[i]);
                addEdge(n+2*i-1,u[i],oo);addEdge(n+2*i-1,v[i],oo);
                addEdge(u[i],n+2*i,oo);  addEdge(v[i],n+2*i,oo);
            }
            N=n+2*m+2;
        }
        bool bfs()
        {
            mem(dis,42);mem(vis,0);
            while(Q.size())Q.pop();
            dis[s]=0;vis[s]=1;Q.push(s);
            while(Q.size())
            {
                int now=Q.front();Q.pop();
                for(int i=first[now];i!=-1;i=e[i].next)
                    if(e[i].f && !vis[e[i].v])
                    {
                        Q.push(e[i].v);
                        dis[e[i].v]=dis[now]+1;
                        vis[e[i].v]=1;
                    }
            }
            return vis[t];
        }
        LL dfs(int x,LL a)
        {
            if(x==t || a==0)return a;
            LL flow=0,tmp;
            for(int& i=cur[x];i!=-1;i=e[i].next)
                if(dis[x]+1==dis[e[i].v] && (tmp=dfs(e[i].v,min(a,e[i].f)))>0)
                {
                    e[i].f-=tmp;e[i^1].f+=tmp;
                    a-=tmp;flow+=tmp;
                    if(a==0)break;
                }
            return flow;
        }
        LL maxflow()
        {
            LL flow=0;
            while(bfs())
            {
                for(int i=1;i<=N;i++)cur[i]=first[i];
                flow+=dfs(s,oo);
            }
            return flow;
        }
    }fyh;
    void solve1()
    {
        LL ans=0;
        for(int i=1;i<=n;i++)ans+=max(ad[i],ap[i]);
        printf("%lld
    ",ans);
        return;
    }
    void solve2()
    {
         fyh.init_build();
         LL sum=0;
         for(int i=1;i<=n;i++)sum+=(ad[i]+ap[i]);
         for(int i=1;i<=m;i++)sum+=(AD[i]+AP[i]);
         printf("%lld",sum-fyh.maxflow());
    }
    int main()
    {
        n=(int)read();m=(int)read();
        for(int i=1;i<=n;i++)ap[i]=read(),ad[i]=read();
        for(int i=1;i<=m;i++)u[i]=(int)read(),v[i]=(int)read(),AD[i]=read(),AP[i]=read(),AX[i]=read();
        if(m==0)solve1();   
        else solve2(); 
        return 0;
    }
    View Code
  • 相关阅读:
    Problem: 八中上厕所
    Problem: 最短路上的统计
    股票买卖问题
    Redis(十二)——Redis为什么是单线程的?
    链表题汇总
    Redis(十一)——集群模式
    Redis(十)——哨兵模式
    Redis(九)——主从复制
    Redis(八)——客户端与服务器
    Redis(七)——事件
  • 原文地址:https://www.cnblogs.com/FYH-SSGSS/p/6480574.html
Copyright © 2011-2022 走看看