タイトル
\(〜\)
BZOJ 1449
LUOGU 4307
説明
バスケットボールリーグでは、そこ(N \)\チーム、支出のチームは、スクリーニングの結果であり、彼らの関係、具体的には、\(私は\)チームがあり、シーズンの総支出の\ (^ 2 + D_IタイムズC_I \ X \ Y ^ 2回、D_I \ルC_I \) 。(マルチウェル上の選手に多くの賞金を獲得するために、)\(X、Yの\は)唯一のチームに今シーズン、スクリーニングの結果を表しています。今シーズンは各チームが作られた、半分に達した(a_iを\)\勝\(b_i \)敗北。そして、そこに\(m個\)があることを一致します。リーグのチームが求める最低限の総支出はどのくらいです。
入力
最初の行\(N、Mの\)
次に\(N- \)線各\(4 \)整数\(a_iを、b_i、C_I、
D_I \) 、次いで、次の\(Mの\)線各2整数\(S \)、\ (のt \)を表し\(複数可\)の注目は、2つのチームの間で複数のゲームであってもよいし、チームとTTのチーム間の試合があるでしょう。
出力
リーグと収益のすべてのチームの最小値を表す整数。
サンプル入力
3 3
1 0 2 1
1 1 10 1
0 1 3 3
1 2
2 3
3 1
サンプル出力
43
ヒント
对于20%的数据\(Mの\ 20 \ \ 10.0 \ 2 \ K) ;
100%对于的数据1000.0 \ \ M \ 5000.0 \ \(2 \ K D_I \ C_I \ a_iを\ 10.0、b_i \ 50 \) 。
分析
- すべてのゲーム2つのチームが否定していると仮定すると、最初のリターンを計算します。
- 各ゲーム、1つのチームの勝利を考えてみましょう。
- \(ソースS \)する(Iゲーム\)を\接続された容量の側1,0のコスト。
- その後、増分費用を考慮してください。収入はより生成されたゲームに勝ちます。その\((C×(W + 1)^ 2 + D *(L-1)^ 2) - (C *とW ^ 2 + D * L ^ 2)= 2ワット* C-2L * D + C + D \) 。
- チームのために、想定した後\(M \)参加フィールド\(X \)フィールドを、その後、最初の\(W =勝利は、L = X + \を失う)、それぞれが勝利した後++ワット\(、Lを- 〜 - \) 。
- 我々\(チーム\)には、(T \シンク)\でも\(X \)勝っ表す、エッジ\(J \)ゲームに勝つために相対的な\(J-1 \)フィールドをとき収入が増加します。
- 増加によるものなので、我々は正確さを保証することができます。
- \(ANS = \)すべてのチーム最初の利益\(+ \)最小コスト最大フローコスト。
- 配列の範囲は、そうでない場合は、慎重に検討評価の予期しない結果を享受します。
コード
#include<bits/stdc++.h>
using namespace std;
const int maxn=5010,maxm=6010,maxe=1e5+10,inf=0x3f3f3f3f;
char buf[1<<15],*fs,*ft;
inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; }
template<typename T>inline void read(T &x)
{
x=0;
T f=1, ch=getchar();
while (!isdigit(ch) && ch^'-') ch=getchar();
if (ch=='-') f=-1, ch=getchar();
while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar();
x*=f;
}
char Out[1<<24],*fe=Out;
inline void flush() { fwrite(Out,1,fe-Out,stdout); fe=Out; }
template<typename T>inline void write(T x)
{
if (!x) *fe++=48;
if (x<0) *fe++='-', x=-x;
T num=0, ch[20];
while (x) ch[++num]=x%10+48, x/=10;
while (num) *fe++=ch[num--];
*fe++='\n';
}
int ver[maxe],edge[maxe],Next[maxe],cost[maxe],head[maxm],len=1;
inline void add(int x,int y,int z,int c)
{
ver[++len]=y,edge[len]=z,cost[len]=c,Next[len]=head[x],head[x]=len;
ver[++len]=x,edge[len]=0,cost[len]=-c,Next[len]=head[y],head[y]=len;
}
int s,t;
int dist[maxm];
bool vis[maxm];
inline bool spfa()
{
memset(dist,0x3f,sizeof(dist));
memset(vis,0,sizeof(vis));
queue<int>q;q.push(s);
dist[s]=0,vis[s]=1;
while (!q.empty())
{
int x=q.front();
q.pop();
vis[x]=0;
for (int i=head[x]; i; i=Next[i])
{
if (!edge[i]) continue;
int y=ver[i];
if (dist[y]>dist[x]+cost[i])
{
dist[y]=dist[x]+cost[i];
if (!vis[y]) q.push(y),vis[y]=1;
}
}
}
if (dist[t]==inf) return false;
else return true;
}
int ans;
inline int get(int x,int low)
{
vis[x]=1;
if (x==t) return low;
int tmp=low;
for (int i=head[x]; i; i=Next[i])
{
int y=ver[i];
if (edge[i] && dist[y]==dist[x]+cost[i] && (!vis[y] || y==t))
{
int a=get(y,min(tmp,edge[i]));
if (a>0)
{
ans+=a*cost[i];
edge[i]-=a;
edge[i^1]+=a;
if (!(tmp-=a)) break;
}
}
}
return low-tmp;
}
inline void NetFlow()
{
while (spfa())
{
vis[t]=1;
while (vis[t])
{
memset(vis,0,sizeof(vis));
get(s,inf);
}
}
}
typedef int iarr[maxn];
iarr win,lose,c,d,In;
int main()
{
int n,m;read(n);read(m);
s=0,t=n+m+1;
for (int i=1; i<=n; ++i) read(win[i]),read(lose[i]),read(c[i]),read(d[i]);
for (int i=1,x,y; i<=m; ++i) add(s,i,1,0),read(x),read(y),add(i,x+m,1,0),add(i,y+m,1,0),++In[x],++In[y];
for (int i=1; i<=n; ++i) lose[i]+=In[i];
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<=n; ++i)
for (int j=1; j<=In[i]; ++j) add(i+m,t,1,2*c[i]*win[i]+c[i]+d[i]-2*d[i]*lose[i]),--lose[i],++win[i];
NetFlow();
write(ans);
flush();
return 0;
}