bzoj1449 [JSOI2009]球队收益

Description

Input

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

orz huzecong

神犇的想法果然与众不同

首先看上去像网络流。这样就够了

先假设每场比赛两队都是输的,那么接下来转换的时候只要把其中一对变成赢的就好了。

考虑一支球队已经赢了x场输了y场现在要把输的y场之一变成赢的,考虑这样对答案的影响

原来是C[i]*x^2+D[i]*y^2,现在是C[i]*(x+1)^2+D[i]*(y-1)^2

那么在这支球队赢x场输y场的时候把一场输的变成赢的,对答案的贡献就是两个相减

对于一支一开始赢x场输y场的球队,我们向T连边,代价是从(x,y)变成(x+1,y-1)的代价。

然后还有从(x+1,y-1)到(x+2,y-2)……

因为是最小费用最大流,正确性显然

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<ctime>
#define LL long long
#define inf 0x3ffffff
#define S 0
#define T n+m+1
#define N 6010
using namespace std;
inline LL read()
{
    LL x=0,f=1;char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
    while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
    return x*f;
}
struct edge{int to,next,from,v,c;}e[10*N];
struct match{int x,y;}M[100010];
int head[N],from[N],dist[N],q[N];
bool mrk[N];
int n,m,ans,cnt=1;
int a[N],b[N],C[N],D[N];
inline void ins(int u,int v,int w,int c)
{
	e[++cnt].to=v;
	e[cnt].v=w;
	e[cnt].c=c;
	e[cnt].from=u;
	e[cnt].next=head[u];
	head[u]=cnt;
}
inline void insert(int u,int v,int w,int c)
{
	ins(u,v,w,c);
	ins(v,u,0,-c);
}
inline bool spfa()
{
	for(int i=0;i<=T;i++)dist[i]=inf;
	int t=0,w=1;
	dist[S]=0;q[0]=S;mrk[S]=1;
	while (t!=w)
	{
		int now=q[t++];if (t==6005)t=0;
		for (int i=head[now];i;i=e[i].next)
			if(e[i].v&&dist[now]+e[i].c<dist[e[i].to])
			{
				dist[e[i].to]=dist[now]+e[i].c;
				from[e[i].to]=i;
				if (!mrk[e[i].to])
				{
					mrk[e[i].to]=1;
					q[w++]=e[i].to;
					if(w==6005)w=0;
				}
			}
		mrk[now]=0;
	}
	return dist[T]!=inf;
}
inline void mcf()
{
	int x=inf;
	for (int i=from[T];i;i=from[e[i].from])
		x=min(x,e[i].v);
	for (int i=from[T];i;i=from[e[i].from])
	{
		e[i].v-=x;
		e[i^1].v+=x;
		ans+=x*e[i].c;
	}
}
int main()
{
	n=read();m=read();
	for (int i=1;i<=n;i++)
	{
		a[i]=read();
		b[i]=read();
		C[i]=read();
		D[i]=read();
	}
	for(int i=1;i<=m;i++)
	{
		M[i].x=read();
		M[i].y=read();
		b[M[i].x]++;
		b[M[i].y]++;
		insert(S,i,1,0);
		insert(i,m+M[i].x,1,0);
		insert(i,m+M[i].y,1,0);
	}
	for (int i=1;i<=n;i++)
		ans+=a[i]*a[i]*C[i]+b[i]*b[i]*D[i];
	for (int i=1;i<=m;i++)
	{
		int x=M[i].x,y=M[i].y;
		insert(m+x,T,1,2*a[x]*C[x]-2*b[x]*D[x]+C[x]+D[x]);
		a[x]++;b[x]--;
		insert(m+y,T,1,2*a[y]*C[y]-2*b[y]*D[y]+C[y]+D[y]);
		a[y]++;b[y]--;
	}
	while (spfa())mcf();
	printf("%d\n",ans);
	return 0;
}

  

S向所有比赛连边,所有比赛向两队连边。所有队伍

时间: 2024-10-21 01:58:07

bzoj1449 [JSOI2009]球队收益的相关文章

bzoj 1449 [JSOI2009]球队收益(费用拆分,最小费用流)

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 547  Solved: 302[Submit][Status][Discuss] Description Input 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 HINT Source [思路] 费用拆分,

BZOJ 1449: [JSOI2009]球队收益( 最小费用最大流)

先考虑假如全部输了的收益. 再考虑每场比赛球队赢了所得收益的增加量,用这个来建图.. -------------------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<iostre

[JSOI2009]球队收益

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 1124  Solved: 635[Submit][Status][Discuss] Description Input 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 HINT Source 二次费用流模板题.

【bzoj1449/bzoj2895】[JSOI2009]球队收益/球队预算 费用流

题目描述 输入 输出 一个整数表示联盟里所有球队收益之和的最小值. 样例输入 3 3 1 0 2 1 1 1 10 1 0 1 3 3 1 2 2 3 3 1 样例输出 43 题解 费用流 由于存在一个赢一个输,比较难算.我们可以先假设它们都输掉,然后再安排赢的情况. 设fi为i还要打的比赛数目,那么初始的收益为∑ci*wi^2+di*(li+fi)^2. S->每场比赛,容量为1,费用为0. 每场比赛->比赛的两队,容量为1,费用为0. 因为费用的改变是包含平方的,所以我们需要拆边来做. 第

【BZOJ1449/2895】[JSOI2009]球队收益/球队预算 最小费用最大流

[BZOJ2895]球队预算 Description 在一个篮球联赛里,有n支球队,球队的支出是和他们的胜负场次有关系的,具体来说,第i支球队的赛季总支出是Ci*x^2+Di*y^2,Di<=Ci.(赢得多,给球员的奖金就多嘛) 其中x,y分别表示这只球队本赛季的胜负场次.现在赛季进行到了一半,每只球队分别取得了a[i]场胜利和b[i]场失利.而接下来还有m场比赛要进行.问联盟球队的最小总支出是多少. Input 第一行n,m 接下来n行每行4个整数a[i],b[i],Ci,Di 再接下来m行每

BZOJ 1449 JSOI2009 球队收益 费用流

题目大意:给定n支球队,第i支球队已经赢了wini场,输了losei场,接下来还有m场比赛,每个球队最终的收益为Ci?x2i+Di?y2i,其中xi为最终的胜场,yi为最终的负场 求最小化收益 考虑一只球队,其收益与在接下来的比赛中的胜场数关系为: 赢0场 Ci?win2i+Di?(di+losei)2 赢1场 Ci?(wini+1)2+Di?(di+losei?1)2 赢2场 Ci?(wini+2)2+Di?(di+losei?2)2 - 赢di场 Ci?(wini+di)2+Di?lose2

【题解】JSOI2009球队收益 / 球队预算

为什么大家都不写把输的场次增加的呢?我一定要让大家知道,这并没有什么关系~所以 \(C[i] <= D[i]\) 的条件就是来卖萌哒?? #include <bits/stdc++.h> using namespace std; #define maxn 1000000 #define INF 99999999 int n, m, S, T, rec[maxn], flow[maxn], a[maxn], b[maxn]; int ans, tot, c[maxn], d[maxn],

[JSOI2009] 球队收益 (费用流)

终于来发题解啦! pdf版题解 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #include<climits> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9

【BZOJ-1449&amp;2895】球队收益&amp;球队预算 最小费用最大流

1449: [JSOI2009]球队收益 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 648  Solved: 364[Submit][Status][Discuss] Description Input 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 HINT Source 2895: 球队预算