【题目描述】:
【题目解法】:
首先我们考虑lose[i]=sum[i]-win[i] sum[i]表示i队总共进行的比赛数量
这样我们答案的式子就变成:(ci+di)*win[i]^2+sum[i]*sum[i]*d[i]-2*d[i]*sum[i]*win[i]
然后我们考虑将win[i]+1后贡献的式子为:(c[i]+d[i])*(2*win[i]+1)-2*d[i]*sum[i]
然后我们考虑那个麻烦的win[i],也就是说贡献的式子和上一次的win[i]有关
那么我们考虑拆点,把每个点拆成sum[i]个点,每个点表示上次为win[i]这次的贡献
然后我们再对每个点设置一个阈值节点来控制流入每个点的边数
这样建完图后就可以跑一边费用流即可
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=10005;
const int M=200005;
const int INF=32083208;
struct edge {int x,c,f,op,next;} b[M];
int n,m,tot,win[N],lose[N],sum[N],c[N],d[N],s,t;
int a[N],pre[N],cur[N],gap[N],dis[N],ans,q[M]; bool v[N];
inline long long getint()
{
long long x=0; char c=getchar(); bool flag=false;
while ((c!='-')&&((c<'0')||(c>'9'))) c=getchar();
if (c=='-') flag=true,c=getchar();
while ((c>='0')&&(c<='9')) x=x*10+(long long)(c-'0'),c=getchar();
if (flag) return -x; else return x;
}
inline void addedge(int x,int y,int c,int f)
{
++tot; b[tot].x=y; b[tot].c=c; b[tot].f=f; b[tot].op=tot+1; b[tot].next=a[x]; a[x]=tot;
++tot; b[tot].x=x; b[tot].c=0; b[tot].f=-f; b[tot].op=tot-1; b[tot].next=a[y]; a[y]=tot;
}
void init()
{
n=getint(); m=getint(); s=0; t=n+m;
for (int i=1; i<=n; i++)
{
win[i]=getint(); lose[i]=getint();
c[i]=getint(); d[i]=getint();
}
for (int i=1; i<=m; i++)
{
int x=getint(),y=getint(); addedge(s,i,1,0);
addedge(i,x+m,1,0); addedge(i,y+m,1,0);
sum[x]++; sum[y]++; t+=2;
}
for (int i=1; i<=n; i++)
for (int j=1; j<=sum[i]; j++)
{
int x=win[i]+j-1; t++;
addedge(i+m,t,1,(c[i]+d[i])*2*x+c[i]+d[i]-2*d[i]*(sum[i]+lose[i]+win[i]));
}
for (int i=n+m+1; i<=t; i++) addedge(i,t+1,INF,0); t++;
for (int i=1; i<=n; i++) sum[i]+=lose[i]+win[i];
for (int i=1; i<=n; i++) ans+=c[i]*win[i]*win[i]+d[i]*(sum[i]-win[i])*(sum[i]-win[i]);
}
bool spfa()
{
memset(dis,127,sizeof(dis)); memset(v,true,sizeof(v)); int inf=dis[0];
int head=0,tail=1; q[1]=s; v[s]=false; pre[s]=0; dis[s]=0;
while (head<tail)
{
head++; if (head>=M) head=1; int k=q[head]; v[k]=true;
for (int p=a[k];p;p=b[p].next)
{
int pp=b[p].x; if ((dis[k]+b[p].f>=dis[pp])||(b[p].c<=0)) continue;
dis[pp]=dis[k]+b[p].f; pre[pp]=k; cur[pp]=p; if (!v[pp]) continue;
v[pp]=false; tail++; if (tail>=M) tail=1; q[tail]=pp;
}
}
return dis[t]!=inf;
}
void adjust()
{
for (int i=t; i!=s; i=pre[i]) b[cur[i]].c--,b[b[cur[i]].op].c++;
ans+=dis[t];
}
void solve()
{
while (spfa()) adjust();
printf("%d\n",ans);
}
int main()
{
init();
solve();
return 0;
}