动态加点的修车……
不幸把spfa的in_queue的tag打错了(aim打成了now)……跑这么慢一脸懵逼23333
#pragma GCC optimize(2)
#include
#include
#include
#define INF 0x3f3f3f3f
#define MAXN 45
#define MAXM 105
#define MAXP 805
#define MAXE (MAXP+MAXP*MAXP+MAXM)
#define MAX_NODE (MAXP*MAXM+MAXP+2)
using namespace std; int n,m,p;
int a[MAXN];
int time_[MAXP][MAXM];
struct t1{
int to,frm,nxt,c,liu;
t1(){}
t1(int to,int frm,int nxt,int c,int liu):to(to),frm(frm),nxt(nxt),c(c),liu(liu){}
}edge[MAXE<<1]; int cnt_edge=1;
int fst[MAX_NODE];
void addedge(int x,int y,int c,int liu){
edge[++cnt_edge]=t1(y,x,fst[x],c,liu);
fst[x]=cnt_edge;
edge[++cnt_edge]=t1(x,y,fst[y],-c,0);
fst[y]=cnt_edge;
}
const int S=0,T=MAX_NODE-1;
int ans=0;
int dis[MAX_NODE];
int que[MAX_NODE],head,tail;
int in_que[MAX_NODE];
int Frm[MAX_NODE];
inline bool SPFA(int now){
head=tail=0;
que[tail++]=now;
memset(dis,INF,sizeof dis);
dis[now]=0;
in_que[now]=1;
while(head^tail){
now=que[head++];
if(head==MAX_NODE) head=0;
for(register int tmp=fst[now];tmp;tmp=edge[tmp].nxt){
int aim=edge[tmp].to;
if(edge[tmp].liu&&dis[aim]>dis[now]+edge[tmp].c){
dis[aim]=dis[now]+edge[tmp].c;
Frm[aim]=tmp;
if(!in_que[aim]) que[tail++]=aim,in_que[aim]=1;
if(tail==MAX_NODE) tail=0;
}
}
in_que[now]=0;
}
return dis[T]!=INF;
}
inline void FLOW(){
int a,b,rec=0,tmp;
tmp=edge[Frm[T]].frm;
a=tmp/p,b=tmp%p;
if(!b) --a,b=p;
for(register int i=Frm[T];i;i=Frm[edge[i].frm]){
rec+=edge[i].c;
--edge[i].liu;
++edge[i^1].liu;
}
ans+=rec;
if(b==1) return ;
addedge(p*a+b-1,T,0,1);
for(register int i=1,tmp=p*a+b-1,tmp1=p+2-b;i<=n;++i)
addedge(i,tmp,tmp1*time_[i][a],1);
}
int read_x;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",a+i),p+=a[i];
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
scanf("%d",&time_[i][j]);
for(register int i=1;i<=n;++i){
addedge(S,i,0,a[i]);
for(register int j=1;j<=m;++j)
addedge(i,p*(j+1),time_[i][j],1);
}
for(int i=1;i<=m;++i) addedge(p*(i+1),T,0,1);
while(SPFA(S))
FLOW();
printf("%d",ans);
return 0;
}