1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
| #include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <cctype>
using namespace std;
namespace fast_io {
//...
}using namespace fast_io;
const int MAXN = 100000,MAXM = 2000000;
struct Edge{
int from,to;
int cap,flow;
int cost,nex;
}edge[MAXM];
int n,m,s,t,sum = 0;
int ff = 0,cc = 0,p[MAXN],ti[1000][1000];
int fir[MAXN],ecnt = 2;
void addedge(int a,int b,int c,int d){
edge[ecnt] = (Edge){a,b,c,0,d,fir[a]};
fir[a] = ecnt++;
edge[ecnt] = (Edge){b,a,0,0,-d,fir[b]};
fir[b] = ecnt++;
}
int dis[MAXN],instack[MAXN],pree[MAXN];
queue<int> q;
bool spfa(){
while(!q.empty()) q.pop();
memset(dis,0x3f,sizeof(dis));
memset(instack,0,sizeof(instack));
q.push(s);dis[s] = 0;
while(!q.empty()){
int nown = q.front();q.pop();
instack[nown] = 0;
for(int nowe = fir[nown];nowe;nowe = edge[nowe].nex){
Edge e = edge[nowe];
if(dis[e.to] > dis[nown] + e.cost && e.cap > e.flow){
dis[e.to] = dis[nown] + e.cost;
pree[e.to] = nowe;
if(instack[e.to] == 0){
q.push(e.to);
instack[e.to] = 1;
}
}
}
}
return dis[t] < 0x3f3f3f3f;
}
void argument(){
int nown = t,nowe = 0,limit = 0x3f3f3f3f;
while(nown != s){
nowe = pree[nown];
limit = min(limit,edge[nowe].cap - edge[nowe].flow);
nown = edge[nowe].from;
}
nown = t;
while(nown != s){
nowe = pree[nown];
edge[nowe].flow += limit;
edge[nowe^1].flow -= limit;
nown = edge[nowe].from;
}
ff += limit,cc += limit * dis[t];
}
void init(){
read(n),read(m);
for(int i = 1;i<=n;i++){
read(p[i]);
sum += p[i];
}
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
read(ti[i][j]);
}
}
}
void solve(){
s = m*sum + n + 1,t = m*sum + n + 2;
for(int i = 1;i<=n;i++)
addedge(s,m*sum + i,p[i],0);
for(int j = 1;j<=m;j++){
addedge(j,t,1,0);
for(int i = 1;i<=n;i++){
addedge(m*sum + i,j,1,ti[i][j]);
}
}
while(spfa()){
argument();
int x = edge[pree[t]].from;
addedge(x+m,t,1,0);
for(int i = 1;i<=n;i++){
addedge(m*sum + i,x+m,1,ti[i][(x-1)%m+1]*((x+m-1)/m+1));
}
}
print(cc),print('\n');
}
int main(){
init();
solve();
flush();
return 0;
}
|