zoukankan      html  css  js  c++  java
  • [模拟赛FJOI Easy Round #2][T3 skill] (最小割+最大权闭合子图(文理分科模型))

    【题目描述】

    天上红绯在游戏中扮演敏剑,对于高攻击低防御的职业来说,爆发力显得非常重要,为此,她准备学习n个技能,每个技能都有2个学习方向:物理攻击和魔法攻击。对于第i个技能,如果选择物理攻击方向,会增加ap_i的爆发力,如果选择魔法攻击的方向,会增加ad_i的爆发力。此外,还有一些combo,一个combo由两个技能组成,对于第i个combo,如果他们都是魔法攻击,会额外增加AD_i的爆发力,如果他们都是物理攻击,会额外增加AP_i的爆发力,如果他们不属于同一类型,会减少AX_i的爆发力。她找到了你,请你帮她选择技能的类型,产生最大的爆发力。(说明:每个技能都必须学习)

    【输入数据】

    第一行2个正整数n,m,表示技能的个数和combo的个数

    接下来n行每行2个正整数,描述一个技能的ap_i,ad_i

    接下来m行每行5个正整数u,v,AD_i,AP_i,AX_i,描述一个combo,表示技能u和技能v产生combo

    【输出数据】

    一行,一个整数,表示最大的爆发力

    【样例输入】

    2 1
    50 5
    10 20
    1 2 100 50 50

    【样例输出】

    125

    【样例解释】

    均选择魔法攻击,获得5+20+100=125的爆发力

    【数据范围】

    测试点编号

    n

    m

    1

    5

    5

    2

    50

    100

    3

    100000

    0

    4

    500000

    0

    5-7

    1000

    3000

    8-10

    10000

    40000

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

    Solution

    模型:最小割,最大权闭合子图

    来自出题者的题解:可以先看作我们把所有的技能的收益(不包括亏损AX)都获得了,然后在这个获益中扣除最小的代价

    建图:

    对于每个技能,建边(S,u,ap),(u,T,ad)

    对于每个combo,拆点,对点一建边(S,buf1,AD),(buf1,u,+∞),(buf1,v,+∞)

    对点二建边(buf2,T,AP),(u,buf2,+∞),(v,buf2,+∞)

    跑个最大流算法就行

    #include<stdio.h>
    #include<limits.h>
    #include<string.h>
    #define LL long long
    #define dmin(a,b) ((a)<(b)?(a):(b))
    inline int Rin(){
        int x=0,c=getchar(),f=1;
        for(;c<48||c>57;c=getchar())
            if(!(c^45))f=-1;
        for(;c>47&&c<58;c=getchar())
            x=(x<<1)+(x<<3)+c-48;
        return x*f;
    }
    const int N=500010;
    const int M=40010;
    const LL LINF=LONG_LONG_MAX/3*2;
    LL tot(0);
    int n,m,S,T,ecnt=1,fst[N+M*2];
    struct edge{
        int u,v,nxt;
        LL cap,flow;
    }e[(6*M+2*N)*2];
    inline void link(int x,int y,LL w){
        e[++ecnt].u=x;e[ecnt].v=y;
        e[ecnt].cap=w;e[ecnt].flow=0;
        e[ecnt].nxt=fst[x];fst[x]=ecnt;
        e[++ecnt].u=y;e[ecnt].v=x;
        e[ecnt].cap=0;e[ecnt].flow=0;
        e[ecnt].nxt=fst[y];fst[y]=ecnt;
    }
    bool vis[N+M*2];
    int num[N+M*2],cur[N+M*2],d[N+M*2],p[N+M*2],q[N+M*2];
    void bfs(){
        int hd=0,tl=1;
        q[0]=T;d[T]=0;vis[T]=true;
        while(hd^tl){
            int now=q[hd++];
            for(int j=fst[now];j;j=e[j].nxt)
                if(!vis[e[j].u] && e[j].cap>e[j].flow)
                    vis[e[j].u]=true,
                    d[e[j].u]=d[now]+1,
                    q[tl++]=e[j].u;
        }
    }
    inline LL Agument(){
        LL a=LINF;
        int x=T;
        while(x^S)
            a=dmin(a,e[p[x]].cap-e[p[x]].flow),
            x=e[p[x]].u;
        x=T;
        while(x^S)
            e[p[x]].flow+=a,
            e[p[x]^1].flow-=a,
            x=e[p[x]].u;
        return a;
    }
    LL ISAP(){
        int x(S);
        LL flow(0);
        bfs();
        for(int i=S;i<=T;i++)num[d[i]]++;
        for(int i=S;i<=T;i++)cur[i]=fst[i];
        while(d[S]<T){
            if(!(x^T))
                flow+=Agument(),
                x=S;
            bool advanced=false;
            for(int j=cur[x];j;j=e[j].nxt)
                if(e[j].cap>e[j].flow && d[x]==d[e[j].v]+1){
                    advanced=true;
                    cur[x]=j;
                    p[e[j].v]=j;
                    x=e[j].v;
                    break;
                }
            if(!advanced){
                int mn=T-1;
                for(int j=fst[x];j;j=e[j].nxt)
                    if(e[j].cap>e[j].flow)
                        mn=dmin(mn,d[e[j].v]);
                if(--num[d[x]]==0)break;
                num[d[x]=mn+1]++;
                cur[x]=fst[x];
                if(x^S)x=e[p[x]].u;
            }
        }
        return flow;
    }
    int main(){
        freopen("skill.in","r",stdin);
        freopen("skill.out","w",stdout);
        n=Rin(),m=Rin();
        S=1,T=n+1+m*2+1;
        for(int i=1;i<=n;i++){
            LL ap=Rin(),ad=Rin();
            tot+=ap+ad;
            link(S,i+1,ap);
            link(i+1,T,ad);
        }
        for(int i=1;i<=m;i++){
            int u=Rin(),v=Rin();
            LL AP=Rin(),AD=Rin(),AX=Rin();
            tot+=AP+AD;
            link(u+1,v+1,AX);
            link(v+1,u+1,AX);
            link(S,n+1+i,AD);
            link(n+1+i,u+1,LINF);
            link(n+1+i,v+1,LINF);
            link(n+1+i+m,T,AP);
            link(u+1,n+1+i+m,LINF);
            link(v+1,n+1+i+m,LINF);
        }
        printf("%I64d
    ",tot-ISAP());
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    [LeetCode]Reverse Linked List II
    [LeetCode]Remove Duplicates from Sorted List II
    嵌入式培训学习历程第六天
    嵌入式培训学习历程第五天
    嵌入式培训学习历程第三天
    嵌入式培训学习历程第二天
    嵌入式培训学习历程第一天
    shell编程
    找整除--全国模拟(二)
    最长公共连续子串--全国模拟(二)
  • 原文地址:https://www.cnblogs.com/keshuqi/p/6262443.html
Copyright © 2011-2022 走看看