#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 250


//辺を表す構造体{行先、容量、コスト、逆辺のインデックス}
struct Edge{
	Edge(int arg_to,int arg_capacity,int arg_cost,int arg_rev_index){
		to = arg_to;
		capacity = arg_capacity;
		cost = arg_cost;
		rev_index = arg_rev_index;
	}

	int to,capacity,cost,rev_index;
};

int V; //頂点数
vector<Edge> G[NUM]; //グラフの隣接リスト表現
int dist[NUM]; //最短距離
int pre_node[NUM],pre_edge[NUM]; //直前の頂点と辺
int A[101],B[101][101],T[101];


//fromからtoへ向かう容量capacity,コストcostの辺をグラフに追加する
void add_edge(int from,int to,int capacity,int cost){
	G[from].push_back(Edge(to,capacity,cost,G[to].size()));
	G[to].push_back(Edge(from,0,-cost,G[from].size()-1));
}

//sourceからsinkへの、流量flowの最小費用流を求める
//流せない場合は-1を返す
int min_cost_flow(int source,int sink,int flow){
	int ret = 0;
	while(flow > 0){
		//ベルマンフォード方により、source-sink間最短経路を求める
		for(int i = 0; i < V; i++)dist[i] = BIG_NUM;
		dist[source] = 0;
		bool update = true;
		while(update){
			update = false;
			for(int node_id = 0; node_id < V; node_id++){
				if(dist[node_id] == BIG_NUM)continue;
				for(int i = 0; i < G[node_id].size(); i++){
					Edge &e = G[node_id][i];
					if(e.capacity > 0 && dist[e.to] > dist[node_id]+e.cost){
						dist[e.to] = dist[node_id]+e.cost; //node_idを経由した方が早い場合
						pre_node[e.to] = node_id;
						pre_edge[e.to] = i;
						update = true;
					}
				}
			}
		}

		if(dist[sink] == BIG_NUM){
			//これ以上流せない
			return -1;
		}

		//source-sink間最短路に沿って目いっぱい流す
		int tmp_flow = flow;
		for(int node_id = sink; node_id != source; node_id = pre_node[node_id]){
			tmp_flow = min(tmp_flow,G[pre_node[node_id]][pre_edge[node_id]].capacity);
		}
		flow -= tmp_flow;
		ret += tmp_flow*dist[sink];
		for(int node_id = sink; node_id != source; node_id = pre_node[node_id]){
			Edge &e = G[pre_node[node_id]][pre_edge[node_id]];
			e.capacity -= tmp_flow;
			G[node_id][e.rev_index].capacity += tmp_flow;
		}
	}
	return ret;
}

int main(){

	int N,M,K;
	scanf("%d %d %d",&N,&M,&K);

	for(int i = 0; i < N; i++)scanf("%d",&A[i]);

	for(int i = 0; i < M; i++){
		for(int k = 0; k < N; k++)scanf("%d",&B[i][k]);
	}

	for(int i = 0; i < M; i++)scanf("%d",&T[i]);

	int source = 0,sink = 1,first_branch = 2,second_branch = 3,me = 4,index = 5;

	add_edge(source,first_branch,N,0); //全体の流量をNに設定する
	add_edge(first_branch,me,N,0); //自分に最大N流せるようにする
	add_edge(first_branch,second_branch,N-K,0); //最大でも友達にはN-Kしか流せないようにする

	int friend_index[M],report_index[N];

	for(int i = 0; i < M; i++){
		friend_index[i] = index++;
		add_edge(second_branch,friend_index[i],T[i],0); //友達iに流量T[i]の辺を張る
	}

	for(int i = 0; i < N; i++){
		report_index[i] = index++;
		add_edge(report_index[i],sink,1,0); //レポートからsinkへ辺を張る
	}

	for(int i = 0; i < N; i++){
		add_edge(me,report_index[i],1,-A[i]); //自分からレポートに、負のコストの辺を張る
	}

	for(int i = 0; i < M; i++){
		for(int k = 0; k < N; k++){
			add_edge(friend_index[i],report_index[k],1,-B[i][k]); //友達iからレポートkに、負のコストの辺を張る
		}
	}

	V = index;

	printf("%d\n",-min_cost_flow(source,sink,N));

	return 0;
}



Measured memory_bytes: 3476