门边少女 WBQ 想要给她的男朋友买礼物。
礼物有 n 种,每种礼物有一个价格 ai ,如果 WBQ 买了礼物 i,那么她需要付出 ai 的代价。 同时,还有 m 对关系 (pi, qi, bi) ,表示 WBQ 的男朋友如果同时收到了礼物 pi 和礼物 qi ,那 么他的心情就会变好 bi 。
礼物有 n 种,每种礼物有一个价格 ai ,如果 WBQ 买了礼物 i,那么她需要付出 ai 的代价。 同时,还有 m 对关系 (pi, qi, bi) ,表示 WBQ 的男朋友如果同时收到了礼物 pi 和礼物 qi ,那 么他的心情就会变好 bi 。
WBQ 的零花钱有限。设她最终购买礼物一共花费了 A,使 WBQ 的男朋友心情变好了 B, 请你最大化 B/A;
首先这看上去是一个01分数规划+网络流。
还记得profit吗?
于是我考试就这样写的。
20.。。。卡成暴力分,原因是这个题卡精度,然后我define double int 65 tle 35
这是为什么。这个时候,这道题实际就是非朴素建边了。
对于每个点,选择它需要付出的代价为 2gai − degi ,对于每条边,割断它需要付出的代价就是它本身的 bi ,直接建图跑最小割即可。
#include<bits/stdc++.h>
using namespace std;
#define in get_int()
namespace FastIO{
const int L=1<<15;
char buf[L],*S,*T;
char getchar(){
if(S==T){T=(S=buf)+fread(buf,1,L,stdin);if(S==T)return EOF;}
return *S++;
}
char read_char(){char c=getchar();while(!(33<=c&&c<=126))c=getchar();return c;}
void get_string(char *s){
char c=getchar();
while(!(33<=c&&c<=126))c=getchar();
while( (33<=c&&c<=126))*s++=c,c=getchar();
*s=0;
}
int get_int(){
int res=0,bj=1;char c=getchar();
while(!isdigit(c)){if(c=='-')bj=-1;c=getchar();}
while(isdigit(c)){res=res*10+c-'0';c=getchar();}
return res*bj;
}
}using FastIO::get_int;using FastIO::get_string;using FastIO::read_char;
const int N=200010;
const int INF=2139062143;
int n,m,s,t;int sum;
int a[N];
struct hh{int x,y;int l;}nex[N<<4],b[N];
int fir[N],SIZE,cur[N];
void add(int x,int y,int l)
{
nex[++SIZE]=(hh){fir[x],y,l};fir[x]=SIZE;
nex[++SIZE]=(hh){fir[y],x,0};fir[y]=SIZE;
}
int d[N];int q[N],head,tail;
bool bfs()
{
head=tail=0;
fill(d,d+t+1,0);
d[t]=1;q[++tail]=t;
while(head<tail)
{
int x=q[++head];
for(int i=fir[x];i;i=nex[i].x)
{
int to=nex[i].y;
if(nex[i^1].l>0&&!d[to])
{
d[to]=d[x]+1;
if(to==s) return 1;
q[++tail]=to;
}
}
}
return 0;
}
int dfs(int x,int f)
{
if(x==t) return f;
int dat=0;
for(int &i=cur[x];i;i=nex[i].x)
{
int to=nex[i].y;
if(nex[i].l>0&&d[to]==d[x]-1)
{
int w=dfs(to,min(f-dat,nex[i].l));
dat+=w,nex[i].l-=w,nex[i^1].l+=w;
if(fabs(dat-f)<0.0001) return f;
}
}
return dat;
}
int dinic()
{
int ans=0;
while(bfs())
{
copy(fir,fir+1+t,cur);
ans+=dfs(s,INF);
}
return ans;
}
void clear()
{
SIZE=1;
fill(fir,fir+t+1,0);
}
void build(int x)
{
clear();
for(int i=1;i<=n;++i) add(s,i,2*a[i]*x);
for(int i=1;i<=m;++i)
{
int x=b[i].x,y=b[i].y;
add(x,y,b[i].l);add(y,x,b[i].l);
add(x,t,b[i].l);add(y,t,b[i].l);
}
}
int main(){
n=in,m=in;s=0;t=n+1;
for(int i=1;i<=n;++i)a[i]=in;
for(int i=1;i<=m;++i)b[i].x=in,b[i].y=in,b[i].l=in,sum+=2*b[i].l;
int l=0,r=700;
while(l<r)
{
int mid=l+r>>1;
build(mid+1);
if(sum-dinic()>0)
l=mid+1;
else r=mid;
}
printf("%d",l);
return 0;
}