题目描述
Flappy Bird是一款风靡一时的休闲手机游戏。玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的管道缝隙。如果小鸟一不小心撞到了水管或者掉在地上的话,便宣告失败。
现在小鸟们遇到了一个难题,他们遇到了一堵巨大的墙,墙上仅有m个洞供他们通过,由于小鸟们的体型不同且墙上洞的形状也不同,所以每种体型的鸟通过每个洞的时间都不同,鸟的体型共有n种,第i种体型的鸟通过第j个洞需要的时间记为T(i,j),且一个洞必须前一只鸟通过之后后一只鸟才能开始通过。
从时刻0开始,鸟开始通过,而每一只鸟的等待时间为从时刻0到自己已经通过洞的时间。现在知道了第i种体型的鸟有pi只,请求出使所有鸟都通过墙的最少的等待时间之和。
网络流
显然的思路,用网络流做。
对每个洞拆点,i.j表示第i个洞被通过这个洞的倒数第j只鸟通过。
然后连边跑费用流。
然而边数太多直接爆炸,怎么办?
注意到i.j没被流i.j+1就绝不可能被流。
因此动态加边,初始只连所有到x.1的。
目前连到x.y,流成功一次加上所有到x.y+1的边。
然后莫名很慢,所以这里本辣鸡加上了对只有一个洞的特判(面向数据编程)
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=100000+10,maxm=7000000+10,inf=1000000000;
int h[maxn],d[maxn],now[maxn],go[maxm],dis[maxm],co[maxm],fx[maxm],next[maxm];
int id[150][850],di[150*850+10][2],time[50][150],a[50],w[850];
bool bz[maxn];
int i,j,k,l,r,s,t,n,m,p,tot,top,ans,last;
void add(int x,int y,int z,int c,int d){
go[++tot]=y;
dis[tot]=z;
co[tot]=c;
fx[tot]=tot+d;
next[tot]=h[x];
h[x]=tot;
}
int dfs(int x,int flow,int las,int cost){
if (x==t){
ans+=flow*cost;
last=las;
return flow;
}
bz[x]=1;
int r=now[x],k;
while (r){
if (!bz[go[r]]&&dis[r]&&d[x]==d[go[r]]+co[r]){
k=dfs(go[r],min(flow,dis[r]),x,cost+co[r]);
if (k){
dis[r]-=k;
dis[fx[r]]+=k;
now[x]=r;
return k;
}
}
r=next[r];
}
return now[x]=0;
}
bool change(){
int tmp=inf,i,r;
fo(i,s,t)
if (bz[i]){
r=h[i];
while (r){
if (!bz[go[r]]&&dis[r]&&d[go[r]]+co[r]-d[i]<tmp) tmp=d[go[r]]+co[r]-d[i];
r=next[r];
}
}
if (tmp==inf) return 0;
fo(i,s,t)
if (bz[i]) d[i]+=tmp;
return 1;
}
int read(){
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
int main(){
n=read();m=read();
fo(i,1,n) a[i]=read(),p+=a[i];
fo(i,1,n)
fo(j,1,m)
time[i][j]=read();
if (m==1){
top=0;
fo(i,1,n)
fo(j,1,a[i]) w[++top]=time[i][1];
sort(w+1,w+p+1);
fo(i,1,p) ans+=w[i]*(p-i+1);
printf("%d\n",ans);
return 0;
}
s=1;t=p*m+n+2;
fo(i,1,n){
add(s,i+1,a[i],0,1);
add(i+1,s,0,0,-1);
}
top=n+1;
fo(i,1,m)
fo(j,1,p){
id[i][j]=++top;
di[top][0]=i;
di[top][1]=j;
if (j==1)
fo(k,1,n){
add(k+1,id[i][j],1,time[k][i]*j,1);
add(id[i][j],k+1,0,-time[k][i]*j,-1);
}
if (j<=p){
add(id[i][j],t,1,0,1);
add(t,id[i][j],0,0,-1);
}
}
do{
fo(i,s,t) now[i]=h[i];
fill(bz+s,bz+t+1,0);
while (dfs(s,inf,-1,0)){
r=id[di[last][0]][di[last][1]+1];
fo(i,1,n){
add(i+1,r,1,time[i][di[last][0]]*(di[last][1]+1),1);
add(r,i+1,0,-time[i][di[last][0]]*(di[last][1]+1),-1);
}
fill(bz+s,bz+t+1,0);
}
}while (change());
printf("%d\n",ans);
}