bzoj1449 JSOI2009 球隊收益

2022-05-01 06:30:09 字數 1655 閱讀 5409

time limit: 5 sec  memory limit: 64 mb

submit: 1131  solved: 640

[submit][status][discuss]

乙個整數表示聯盟裡所有球隊收益之和的最小值。

3 31 0 2 1

1 1 10 1

0 1 3 3

1 22 3

3 143

分析:很妙的idea.

首先要能想到用最小費用最大流求解. 為什麼呢?把比賽當作點,每一場比賽有兩種結果,那麼就可以認為容量為1. 要使得收益最小,加上費用,就是求最小費用最大流了.

但是確定不了每場比賽的收益. 

乙個非常巧妙的做法:

我們考慮費用的增量:多贏一場比賽產生的收益。

即(c(w + 1)^2 + d(l − 1)^2 ) − (cw^2 + dl^2 ) = 2wc − 2ld + c + d。

對於第i支隊伍,假設後m場中i參加的有x場,那麼最初w = win,

l = lose + x,之後每贏一場w + +,l − −。我們從第i支隊伍的點向匯連x條邊,

分別代表第i支隊伍贏了j場比賽時相對贏j − 1場時收益的增量。由於增量一定

越來越大(平方嘛),所以流量最先流過的一定是費用較小的邊,即j最小的邊。

答案即所有隊伍最初收益+最小費用最大流的費用。

費用遞增模型可以採用拆邊的方式跑費用流. 先確定最初狀態,保證以後的費用都是遞增的,這是演算法正確性的保證!

#include #include 

#include

#include

#include

using

namespace

std;

const

int maxn = 10010,inf = 0x7fffffff

;int

n,m,win[maxn],lose[maxn],c[maxn],d[maxn];

inta[maxn],b[maxn],ans,s,t,vis[maxn],vis2[maxn];

int head[maxn],to[maxn * 6],nextt[maxn * 6],w[maxn * 6],cost[maxn * 6],tot = 2

;void add(int x,int y,int z,int

p)bool

spfa()}}

}return d[t]

}int dfs(int u,int

f)

int res = 0

; vis2[u] = 1

;

for (int i = head[u];i;i =nextt[i])

}return

res;

}void

dinic()

intmain()

for (int i = 1; i <= n; i++)

ans += win[i] * win[i] * c[i] + lose[i] * lose[i] *d[i];

for (int i = 1; i <= m; i++)

dinic();

printf(

"%d\n

",ans);

return0;

}

JSOI2009 bzoj1449 球隊收益

description input output 乙個整數表示聯盟裡所有球隊收益之和的最小值。首先假設全輸,然後給每場比賽分配乙個贏家,每個隊伍每多贏一場多獲得的收益作為費用。但是有乙個問題,如何保證每次走的是對應的邊?也就是,如何保證贏第一場的時候增加的收益是贏一場減贏零場,而不是贏兩場減贏一場?...

bzoj1449 JSOI2009 球隊收益

傳送門 感覺就是費用流呀。可以發現這道題與之前的費用流題有所不同,因為乙個球隊不論輸還是贏都會獲得收益。這裡就要用到乙個技巧,我們可以假裝比賽雙方都輸,然後修改贏的就ok辣。然後就是每個人向終點連邊,這裡的費用隨著流量的變化而變化,所以我們要用到拆邊法。考慮乙個人從贏win i 次 輸lose i ...

BZOJ1449 JSOI2009 球隊收益

bzoj luogu 在乙個籃球聯賽裡,有 n 支球隊,球隊的支出是和他們的勝負場次有關係的,具體來說,第i支球隊的賽季總支出是 c i times x 2 d i times y 2,d i le c i 其中 x,y 分別表示這只球隊本賽季的勝負場次。現在賽季進行到了一半,每只球隊分別取得了 a...