zoukankan      html  css  js  c++  java
  • 【BZOJ1449】 球队收益

    BZOJ1449 球队收益

    img

    img

    Output

    一个整数表示联盟里所有球队收益之和的最小值。

    Sample Input

    3 3
    1 0 2 1
    1 1 10 1
    0 1 3 3
    1 2
    2 3
    3 1

    Sample Output

    43

    我们先假设所有的球队都赢,算出答案。然后每场比赛都要提供一个输的场次。

    考虑费用流。源点向每场比赛连边,每场比赛向两只队伍连边,队伍再向汇点连边。

    注意到一只队伍的得分是关于输的场次的一个二次函数,所以每增加一个输场,增加或减少的收益不一样。所以我们拆边。设(f_{i,k})表示第(i)只队伍输(k)场的收益,则第(a)条边的权值为(f_{i,a}-f_{i,a-1})。然后再跑最小费用流。

    因为这是个开口向上的二次函数,它的二阶导是大于(0)的。 所以(f_{i,a}-f_{i,a-1})单调递增,这么拆边是对的。

    代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 15005
    
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    int n,m;
    int S,T;
    int win[N],lose[N];
    int c[N],d[N];
    int a[N],b[N];
    struct road {
    	int to,next;
    	int f,c;
    }s[N<<4];
    
    int h[N<<2],cnt=1;
    void add(int i,int j,int f,int c) {
    	s[++cnt]=(road) {j,h[i],f,c};h[i]=cnt;
    	s[++cnt]=(road) {i,h[j],0,-c};h[j]=cnt;
    }
    
    int tim[N];
    ll ans;
    ll dis[N];
    queue<int>q;
    int fr[N],e[N];
    bool in[N];
    bool spfa(int S) {
    	memset(dis,0x3f,sizeof(dis));
    	dis[S]=0;
    	q.push(S);
    	while(!q.empty()) {
    		int v=q.front();q.pop();
    		in[v]=0;
    		for(int i=h[v];i;i=s[i].next) {
    			int to=s[i].to;
    			if(s[i].f&&dis[to]>dis[v]+s[i].c) {
    				dis[to]=dis[v]+s[i].c;
    				fr[to]=v;
    				e[to]=i;
    				if(!in[to]) {
    					in[to]=1;
    					q.push(to);
    				}
    			}
    		}
    	}
    	if(dis[T]>1e9) return 0;
    	ans+=dis[T];
    	for(int i=T;i;i=fr[i]) {
    		s[e[i]].f--;
    		s[e[i]^1].f++;
    	}
    	return 1;
    }
    
    int main() {
    	n=Get(),m=Get();
    	for(int i=1;i<=n;i++) {
    		win[i]=Get(),lose[i]=Get();
    		c[i]=Get(),d[i]=Get();
    	}
    	T=m+n+1;
    	for(int i=1;i<=m;i++) {
    		a[i]=Get(),b[i]=Get();
    		add(S,i,1,0);
    		tim[a[i]]++,tim[b[i]]++;
    		add(i,a[i]+m,1,0),add(i,b[i]+m,1,0);
    	}
    	for(int i=1;i<=n;i++) {
    		ll last=1ll*c[i]*(win[i]+tim[i])*(win[i]+tim[i])+1ll*d[i]*lose[i]*lose[i],now;
    		ans+=last;
    		for(int j=1;j<=tim[i];j++) {
    			now=1ll*c[i]*(win[i]+tim[i]-j)*(win[i]+tim[i]-j)+1ll*d[i]*(lose[i]+j)*(lose[i]+j);
    			add(i+m,T,1,now-last);
    			last=now;
    		}
    	}
    	while(spfa(S));
    	cout<<ans;
    	return 0;
    }
    
    
  • 相关阅读:
    java8
    java7
    java6
    java5
    java复习4
    学习笔记
    Reflection笔记
    通过Reflection来获得方法和信息
    學習反射2
    學習反射1
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10567067.html
Copyright © 2011-2022 走看看