/*  It's the next chapter, the ultimate goal  */
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int INF = 1e9;
struct edge {
	int to, flow, cap, cost, rev;
};
struct MinCostMaxFlow {
	int nodes;
	vector <int> curflow, prevedge, prevnode, q;
	vector <int> pot, prio;
	vector <bool> inqueue;
	vector <vector<edge>> graph;
	MinCostMaxFlow() {}
	MinCostMaxFlow(int n): nodes(n), prio(n, 0), curflow(n, 0),
	prevedge(n, 0), prevnode(n, 0), q(n, 0), pot(n, 0), inqueue(n, 0), graph(n) {}
	void addEdge(int source, int to, int capacity, int cost) {
		edge a = {to, 0, capacity, cost, (int) graph[to].size()};
		edge b = {source, 0, 0, - cost, (int) graph[source].size()};
		graph[source].push_back(a);
		graph[to].push_back(b);
	}
	void bellman_ford(int source, vector<int> &dist) {
		fill(dist.begin(), dist.end(), INF);
		dist[source] = 0;
		int qt = 0;
		q[qt ++] = source;
		for(int qh = 0; (qh - qt) % nodes != 0; qh ++) {
			int u = q[qh % nodes];
			inqueue[u] = false;
			for(auto &e : graph[u]) {
				if(e.flow >= e.cap) continue;
				int v = e.to;
				int newDist = dist[u] + e.cost;
				if(dist[v] > newDist) {
					dist[v] = newDist;
					if(!inqueue[v]) {
						inqueue[v] = true;
						q[qt ++ % nodes] = v;
					}
				}
			}
		}
	}
	pair <int, int> minCostFlow(int source, int dest, int maxflow) {
		bellman_ford(source, pot);
		int flow = 0;
		int flow_cost = 0;
		while(flow < maxflow) {
			priority_queue <pair <int, int>, vector<pair<int, int>>, greater <pair <int, int>>> q;
			q.push({0, source});
			fill(prio.begin(), prio.end(), INF);
			prio[source] = 0;
			curflow[source] = INF;
			while(!q.empty()) {
				int d = q.top().first;
				int u = q.top().second;
				q.pop();
				if(d != prio[u]) continue;
				for(int i = 0; i < (int) graph[u].size(); i ++) {
					edge &e=graph[u][i];
					int v = e.to;
					if(e.flow >= e.cap) continue;
					int newPrio = prio[u] + e.cost + pot[u] - pot[v];
					if(prio[v] > newPrio) {
						prio[v] = newPrio;
						q.push({newPrio, v});
						prevnode[v] = u;
						prevedge[v] = i;
						curflow[v] = min(curflow[u], e.cap - e.flow);
					}
				}
			}
			if(prio[dest] == INF) break;
			for(int i = 0; i < nodes; i ++) pot[i] += prio[i];
			int df = min(curflow[dest], maxflow - flow);
			flow += df;
			for(int v = dest; v != source; v = prevnode[v]) {
				edge &e = graph[prevnode[v]][prevedge[v]];
				e.flow += df;
				graph[v][e.rev].flow -= df;
				flow_cost += df * e.cost;
			}
		}
		return {flow, flow_cost};
	}
};
void z_function(vector <int> &z, string &s) {
    int n = (int) s.length();
    z.resize(n);
    for (int i = 1, l = 0, r = 0; i < n; ++ i) {
        if (i <= r) z[i] = min(r - i + 1, z[i - l]);
        while (i + z[i] < n && s[z[i]] == s[i + z[i]]) ++ z[i];
        if (i + z[i] - 1 > r) l = i, r = i + z[i] - 1;
    }
}
int main() {
	ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);

	#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	freopen("error.txt", "w", stderr);
	#endif

	int n; cin >> n;
	string S; cin >> S;
	MinCostMaxFlow Network(n + 2);
	int s = 0, t = n + 1;
	for(int i = 1; i <= t; i ++) Network.addEdge(i - 1, i, INF, 0);
	int m; cin >> m;
	while(m --) {
		string cur; cin >> cur;
		int l = cur.length(), c;
		cin >> c;
		cur = cur + "&" + S;
		vector <int> z;
		z_function(z, cur);
		for(int i = l + 1; i < (int) z.size(); i ++) {
			if(z[i] == l) Network.addEdge(i - l, i, 1, - c);
		}
	}
	int x; cin >> x;
	cout << -1 * Network.minCostFlow(s, t, x).second;

	return 0;
}


/*#include<iostream>
#include<algorithm>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=85*85*8;
const int inf=0x3f3f3f3f;
int head[maxn],to[maxn],nxt[maxn],wei[maxn],cost[maxn],tot=1;
int dis[maxn],pre[maxn],pres[maxn];
bool vis[maxn];
queue<int>que;
int a[85][85],n,m,sum;
int used;
int start,tail;
void add(int x,int y,int z,int w)
{
    tot++,to[tot]=y,nxt[tot]=head[x],head[x]=tot,cost[tot]=w,wei[tot]=z;
    tot++,to[tot]=x,nxt[tot]=head[y],head[y]=tot,cost[tot]=-w,wei[tot]=0;
}
bool spfa()
{
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[start]=0;
    que.push(start);
    int now;
    do{
        now=que.front();
        vis[now]=0;
        que.pop();
        for(int i=head[now];i;i=nxt[i])
        {
            if(dis[to[i]]>dis[now]+cost[i]&&wei[i])
            {
                dis[to[i]]=dis[now]+cost[i];
                pre[to[i]]=now;
                pres[to[i]]=i;
                if(!vis[to[i]])
                {
                    que.push(to[i]);
                    vis[to[i]]=1;
                }
            }
        }
    }while(!que.empty());
    return dis[tail]!=inf;
}
void f()
{
    int now=tail;
    int low=inf;
    while(now!=start)
    {
        low=min(low,wei[pres[now]]);
        now=pre[now];
    }
    used+=low*dis[tail];
    now=tail;
    while(now!=start)
    {
        wei[pres[now]]-=low;
        wei[pres[now]^1]+=low;
        now=pre[now];
    }
}
int num(int x,int y){
	return (x-1)*m+y;
}
int main()
{
	//memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			cin>>a[i][j];
		}
	}
	start=m*n+1,tail=start+1;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if((i+j)&1){
				add(start,num(i,j),1,0);
			}else{
				add(num(i,j),tail,1,0);
			}
			if(i<n){
				if((i+j)&1){
					add(num(i,j),num(i+1,j),1,a[i][j]!=a[i+1][j]);
				}else{
					add(num(i+1,j),num(i,j),1,a[i+1][j]!=a[i][j]);
				}
			}
			if(j<m){
				if((i+j)&1){
					add(num(i,j),num(i,j+1),1,a[i][j]!=a[i][j+1]);
				}else{
					add(num(i,j+1),num(i,j),1,a[i][j+1]!=a[i][j]);
				}
			}
		}
	}
	while(spfa())
        f();
    cout<<used<<endl;
}*//*
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int num[100005];
int main()
{
	int n,m;
	int cas=1;
	while(cin>>n>>m){
		if(n==0&&m==0){
			break;
		}
		for(int i=1;i<=n;i++){
			cin>>num[i];
		}
		sort(num+1,num+1+n);
		cout<<"CASE# "<<cas++<<":"<<endl;
		for(int i=1;i<=m;i++){
			int q;
			cin>>q;
			int ans=lower_bound(num+1,num+1+n,q)-num;
			if(q==num[ans]){
				cout<<q<<" found at "<<ans<<endl;
			}else{
				cout<<q<<" not found"<<endl;
			}
		}
	}
	return 0;
}*//*
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
int head[200005],vis[200005],v[200005];
int tot;
struct node{
	int v,w,d,id,next;
}e[200005];
void add(int u,int v,int w,int d,int id){
	e[tot].v=v;
	e[tot].w=w;
	e[tot].id=id;
	e[tot].d=d;
	e[tot].next=head[u];
	head[u]=tot++;
}
int main(){
	int n,m;
	tot=0;
	memset(head,-1,sizeof(head));
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,to,w;
		cin>>u>>to>>w;
		add(u,to,w,0,i);
		add(to,u,w,1,i);
		v[u]+=w;
		v[to]+=w;
	}

	int dir[200005];
	vis[1]=1;
	queue<int>q;
	q.push(1);
	while(q.size()){
		int u=q.front();
		q.pop();
		for(int i=head[u];i!=-1;i=e[i].next){
			int to=e[i].v;
			if(vis[to])continue;
			v[to]-=2*e[i].w;
			dir[e[i].id]=e[i].d;
			if(v[to]==0&&to!=n){
				vis[to]=1;
				q.push(to);
			}
		}
	}
	for(int i=1;i<=m;i++){
		cout<<dir[i]<<endl;
	}
	return 0;
}*//*
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
int s,t,head[500005],h[500005],tot;
int A[55],b[55],c[55];
int n,m,k;
int str[55];
int r[55],l[55];
struct node{
	int u,v,w,next;
}a[500005];
void add(int u,int v,int w)
{
	a[tot].u=u;
	a[tot].v=v;
	a[tot].w=w;
	a[tot].next=head[u];
	head[u]=tot++;
	a[tot].u=v;
	a[tot].v=u;
	a[tot].w=0;
	a[tot].next=head[v];
	head[v]=tot++;
}
int bfs()
{
	queue<int>q;
	memset(h,-1,sizeof(h));
	h[s]=0;
	q.push(s);
	while(q.size())
	{
		int u=q.front();
		q.pop();
		for(int i=head[u];i!=-1;i=a[i].next)
		{
			int v=a[i].v;
			if(h[v]<0&&a[i].w)
			{
				h[v]=h[u]+1;
				q.push(v);
			}
		}
	}
	return h[t]>0;
}
int dfs(int x,int f)
{
	if(x==t||f==0)return f;
	int flow;
	for(int i=head[x];i!=-1;i=a[i].next)
	{
		int v=a[i].v;
		if(h[v]==h[x]+1&&a[i].w)
		{
			if(flow=dfs(v,min(a[i].w,f)))
			{
				a[i].w-=flow;
				a[i^1].w+=flow;
				return flow;
			}
		}
	}
	return 0;
}
int dinic()
{
	int flow=0;
	while(bfs())
	{
		flow+=dfs(s,inf);
	}
	return flow;
}
int f(int i,int j){
	return A[i]*j*j+b[i]*j+c[i];
}
int num(int i,int j){
	return str[i]+j-l[i];
}
int main()
{
	cin>>n>>m;
	memset(head,-1,sizeof(head));
	int maxx=0;
	int cnt=0;
	for(int i=1;i<=n;i++){
		cin>>A[i]>>b[i]>>c[i];
	}
	for(int i=1;i<=n;i++){
		cin>>l[i]>>r[i];
		str[i]=++cnt;
		cnt+=r[i]-l[i]+1;
		for(int j=l[i];j<=r[i];j++){
			maxx=max(maxx,f(i,j));
		}
	}
	s=0,t=cnt+1;
	for(int i=1;i<=n;i++){
		add(0,str[i],inf);
		for(int j=l[i];j<=r[i];j++){
			add(num(i,j),num(i,j+1),maxx-f(i,j));
		}
		add(num(i,r[i]+1),t,inf);
	}
	for(int i=1;i<=m;i++){
		int u,v,d;
		cin>>u>>v>>d;
		for(int j=l[u];j<=r[u];j++){
			if(j-d>=l[v]&&j-d<=r[v]+1){
				add(num(u,j),num(v,j-d),inf);
			}
		}
	}
	int ans=dinic();
	cout<<maxx*n-ans<<endl;
	return 0;
}*//*
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
using namespace std;
const int inf=0x3f3f3f3f;
int start;
int tail;
int head[150500],to[150500],nxt[150500],wei[150500],cost[150500],tot=1;
int dis[5050],pre[5050],pres[5050];
bool vis[5050];
queue<int>que;
int n,sum,k;
int used;
void add(int x,int y,int z,int w)
{
    tot++,to[tot]=y,nxt[tot]=head[x],head[x]=tot,cost[tot]=w,wei[tot]=z;
    tot++,to[tot]=x,nxt[tot]=head[y],head[y]=tot,cost[tot]=-w,wei[tot]=0;
}
bool spfa()
{
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[start]=0;
    que.push(start);
    int now;
    do{
        now=que.front();
        vis[now]=0;
        que.pop();
        for(int i=head[now];i;i=nxt[i])
        {
            if(dis[to[i]]>dis[now]+cost[i]&&wei[i])
            {
                dis[to[i]]=dis[now]+cost[i];
                pre[to[i]]=now;
                pres[to[i]]=i;
                if(!vis[to[i]])
                {
                    que.push(to[i]);
                    vis[to[i]]=1;
                }
            }
        }
    }while(!que.empty());
    return dis[tail]!=inf;
}
void f()
{

    int maxflow=0;
    while(spfa()){
    	int low=inf;
		int now=tail;
        while(now!=start){
            low=min(low,wei[pres[now]]);
            now=pre[now];
        }
        now=tail;
        while(now!=start){
            wei[pres[now]]-=low;
            wei[pres[now]^1]+=low;
            now=pre[now];
        }
        if(k==0){
    	    maxflow+=low;
    	    continue;
	    }
	    if(used+low*dis[tail]>k){
		    maxflow+=(k-used)/dis[tail];
		    break;
	    }
	    used+=low*dis[tail];
	    maxflow+=low;
	    if(used==k){
		    break;
	    }
    }
   cout<<maxflow<<endl;
}
int main(){
	cin>>n>>k;
	start=1,tail=n;
	int t;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			cin>>t;
			if(t==0)continue;
			add(i,j,t,0);
			add(i,j,k,1);
		}
	}
	f();
	return 0;
}*//*
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m;
int mp[1005][1005],u[10005],v[10005],w[10005];
int f[1005];
vector<int>vec[1005];
set<int>s;
struct node{
	int u,v,w,num;
}edge[50005];
int Find(int x)
{
	return x==f[x]?x:f[x]=Find(f[x]);
}
bool cmp(node x,node y)
{
	return x.w<y.w;
}
void kruskal()
{
	sort(edge+1,edge+1+m,cmp);
	for(int j=1;j<=n;j++)
	{
		f[j]=j;
	}
	for(int i=1;i<=m;i++)
	{
		int cnt=0;
		for(int j=i;j<=m;j++)
		{
			int x=Find(edge[j].u),y=Find(edge[j].v);
			if(x==y)continue;
			f[x]=y;
			//cout<<w[edge[j].num]<<endl;
			s.insert(w[edge[j].num]);
			if(++cnt==n-1)
			{
			    break;
			}
		}
	}
	cout<<s.size()<<endl;
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>u[i]>>v[i]>>w[i];
		vec[w[i]].push_back(i);
	}
	for(int i=1;i<=m;i++){
		if(vec[w[i]].size()==1){
			edge[i].u=u[i],edge[i].v=v[i],edge[i].w=1;
			edge[i].num=i;
		}else{
			edge[i].u=u[i],edge[i].v=v[i],edge[i].w=2;
			edge[i].num=i;
		}
	}
	kruskal();
	return 0;
}*//*
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
#include<string>
using namespace std;
const int inf=0x3f3f3f3f;
int start;
int tail;
int head[150500],to[150500],nxt[150500],wei[150500],cost[150500],tot=1;
int dis[5050],pre[5050],pres[5050];
bool vis[5050];
queue<int>que;
int n,sum,k;
int used,flow;
char str[105];
int numstr[30],numstr1[105][30],num[105];

void add(int x,int y,int z,int w)
{
    tot++,to[tot]=y,nxt[tot]=head[x],head[x]=tot,cost[tot]=w,wei[tot]=z;
    tot++,to[tot]=x,nxt[tot]=head[y],head[y]=tot,cost[tot]=-w,wei[tot]=0;
}
bool spfa()
{
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[start]=0;
    que.push(start);
    int now;
    do{
        now=que.front();
        vis[now]=0;
        que.pop();
        for(int i=head[now];i;i=nxt[i])
        {
            if(dis[to[i]]>dis[now]+cost[i]&&wei[i])
            {
                dis[to[i]]=dis[now]+cost[i];
                pre[to[i]]=now;
                pres[to[i]]=i;
                if(!vis[to[i]])
                {
                    que.push(to[i]);
                    vis[to[i]]=1;
                }
            }
        }
    }while(!que.empty());
    return dis[tail]!=inf;
}

void f()
{
    int now=tail;
    int low=inf;
    while(now!=start)
    {
        low=min(low,wei[pres[now]]);
        now=pre[now];
    }
    used+=low*dis[tail];
    flow+=low;
    now=tail;
    while(now!=start)
    {
        wei[pres[now]]-=low;
        wei[pres[now]^1]+=low;
        now=pre[now];
    }
}

int main(){
	int len;
	cin>>str;
	len=strlen(str);
	for(int i=0;i<strlen(str);i++){
		numstr[str[i]-'a'+1]++;
	}
	cin>>k;
	start=0,tail=30;
	for(int i=1;i<=k;i++){
		cin>>str>>num[i];
		for(int j=0;j<strlen(str);j++){
			numstr1[i][str[j]-'a'+1]++;
		}
	}
	for(int i=1;i<=26;i++){
		if(!numstr[i])continue;
		add(start,i,numstr[i],0);
		for(int j=1;j<=k;j++){
			if(!numstr1[j][i])continue;
			add(i,j+30,numstr1[j][i],j);
		}
	}
	for(int i=1;i<=k;i++){
		add(i+30,tail,num[i],0);
	}
	while(spfa()){
		f();
	}
	if(flow!=len){
		cout<<-1<<endl;
	}else{
		cout<<used<<endl;
	}
	return 0;
}*/
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<queue>
#include<string>
using namespace std;
const int inf=0x3f3f3f3f;
int start;
int tail;
int head[150500],to[150500],nxt[150500],wei[150500],cost[150500],tot=1;
int dis[5050],pre[5050],pres[5050];
bool vis[5050];
queue<int>que;
int n,sum,k,m;
int used;
char str[105][105],s[505];
int v[105];

void add(int x,int y,int z,int w)
{
    tot++,to[tot]=y,nxt[tot]=head[x],head[x]=tot,cost[tot]=w,wei[tot]=z;
    tot++,to[tot]=x,nxt[tot]=head[y],head[y]=tot,cost[tot]=-w,wei[tot]=0;
}
bool spfa()
{
    memset(dis,inf,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[start]=0;
    que.push(start);
    int now;
    do{
        now=que.front();
        vis[now]=0;
        que.pop();
        for(int i=head[now];i;i=nxt[i])
        {
            if(dis[to[i]]>dis[now]+cost[i]&&wei[i])
            {
                dis[to[i]]=dis[now]+cost[i];
                pre[to[i]]=now;
                pres[to[i]]=i;
                if(!vis[to[i]])
                {
                    que.push(to[i]);
                    vis[to[i]]=1;
                }
            }
        }
    }while(!que.empty());
    return dis[tail]!=inf;
}

void f()
{
    int now=tail;
    int low=inf;
    while(now!=start)
    {
        low=min(low,wei[pres[now]]);
        now=pre[now];
    }
    used+=low*dis[tail];
    now=tail;
    while(now!=start)
    {
        wei[pres[now]]-=low;
        wei[pres[now]^1]+=low;
        now=pre[now];
    }
}

int judge(int x,int y){
	int i;
	if(x+strlen(str[y]+1)-1>n)return 0;
	for(i=1;i<=strlen(str[y]+1);i++){
		if(s[x+i-1]!=str[y][i]){
			return 0;
		}
	}
	/*if(i!=strlen(str[y]+1)){
		return 0;
	}*/
	return 1;
}
int main(){
	cin>>n;
	cin>>(s+1);
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>(str[i]+1)>>v[i];
	}
	cin>>k;
	start=0,tail=n+1;
	for(int i=1;i<=n;i++){
		add(i-1,i,k,0);
	}
	add(n,tail,k,0);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			if(judge(i,j)){
				add(i,i+strlen(str[j]+1),1,-v[j]);
			}
		}
	}
	while(spfa()){
		//cout<<used<<endl;
		f();
	}
	cout<<-used<<endl;
	return 0;
}


#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 505, M = 105, K = N*4+N*M*2, inf = 1e9;
int n, m, X, num, len[M], x[N], h[N<<1], f[N<<1], nxt[N<<1], e[K], w[K], c[K], pre[K], q[K<<2];
ll ans, dis[N<<1];
bool vis[N<<1];
char s[N], b[N];
inline void add(int x, int y, int a, int b){
	e[++num]=y, w[num]=a, c[num]=b, pre[num]=h[x], h[x]=num;
	e[++num]=x, w[num]=0, c[num]=-b, pre[num]=h[y], h[y]=num;
}
inline bool spfa(int S, int T){
	memset(dis, -1, sizeof dis), memset(f, 0, sizeof f);
	int r=1;
	q[1]=S, f[S]=inf, dis[S]=0;
	for(int l=1; l<=r; ++l){
		int u=q[l];
		for(int i=h[u]; i; i=pre[i]) if(w[i] && dis[u]+c[i]>dis[e[i]]){
			dis[e[i]]=dis[u]+c[i], f[e[i]]=min(f[u], w[i]), nxt[e[i]]=i^1;
			if(!vis[e[i]]) q[++r]=e[i], vis[e[i]]=1;
		}
		vis[u]=0;
	}
	if(!f[T]) return 0;
	ans+=f[T]*dis[T];
	for(int x=T; x!=S; x=e[nxt[x]]) w[nxt[x]]+=f[T], w[nxt[x]^1]-=f[T];
	return 1;
}
int main() {
	scanf("%d%s%d", &n, s+1, &m), num=1;
	for(int i=1, q, len; i<=m; ++i){
		scanf("%s%d", b+1, &q), len=strlen(b+1);
		for(int j=1; j<=n-len+1; ++j){
			for(int k=1; k<=len; ++k) if(s[j+k-1]!=b[k]) goto nxt;
			add(j*2-1, (j+len-1)*2, 1, q);
			nxt:;
		}
	}
	scanf("%d", &X);
	for(int i=1; i<=n; ++i) x[i]=X;
	int S=0, T=n*2+1;
	add(S, 1, 100, 0), add(n*2, T, 100, 0);
	for(int i=1; i<=n; ++i) add(i*2-1, i*2, 100-x[i], inf), add(i*2-1, i*2, 100, 0);
	for(int i=1; i<n; ++i) add(i*2, i*2+1, 100, 0);
	while(spfa(S, T));
	return printf("%lld", ans%inf), 0;
}


#include <iostream>
#include <vector>
#include <string>
using namespace std;

struct edge
{
    int from, to, cost, cap, flow, n;
};

const int INF = 1e9;

vector<edge> E;
void add_edge(int from, int to, int cost, int cap)
{
    edge e1 = {from, to, cost, cap, 0, E.size()};
    edge e2 = {to, from, -cost, 0, 0, E.size() + 1};
    E.push_back(e1);
    E.push_back(e2);
}

int s, t, n;

long long itr()
{
    vector<int> d(n, INF);
    vector<int> pr(n, -1);
    vector<int> Min(n, INF);
    d[s] = 0;
    while (true)
    {
        bool ch = true;
        for (int i = 0; i < E.size(); ++i)
        {
            int a = E[i].from, b = E[i].to;
            if (E[i].flow < E[i].cap && d[a]!= INF && d[a] + E[i].cost < d[b])
            {
                ch = false;
                d[b] = d[a] + E[i].cost;
                pr[b] = i;
                Min[b] = min(Min[a], E[i].cap - E[i].flow);
            }
        }
        if (ch)
            break;
    }
    //cout << d[t] << " " << Min[t] << endl;
    if (d[t] == 0)
        return 0;
    int v = t;
    int f = Min[t];
    while (true)
    {
        if (v == s)
            break;
        int e = pr[v];
        E[e].flow += f;
        E[e^1].flow -= f;
        v = E[e].from;
    }
    return Min[t] * d[t];
}
long long mincost(int k)
{
    long long ans = 0;
    for (int i = 0; i < k; ++i)
    {
        //cout <<"OK" << endl;
        long long c = itr();
        //cout << c << endl;
        if (c == 0)
            return ans;
        ans += c;
    }
    return ans;
}

int main()
{
    int  m, k;
    string S;
    cin >> n >> S >> m;
    s = 0;
    t = n;
    for (int i = 0; i < n; ++i)
    {
        add_edge(i, i + 1, 0, INF);
    }
    ++n;
    for (int i = 0; i < m; ++i)
    {
        string S1;
        int c;
        cin >> S1 >> c;
        for (int i1 = 0; i1 <= (int)S.size() - S1.size(); ++i1)
        {
            int i2;
            for (i2 = 0; i2 < S1.size(); ++i2)
            {
                if (S[i1 + i2] != S1[i2])
                    break;
            }
            if (i2 == S1.size())
            {
                add_edge(i1, i1 + S1.size(), -c, 1);
            }
        }
        //cout << endl;
    }
    cin >> k;
    cout << -mincost(k) << endl;
    return 0;
}


#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const ll INF = 10000000000;
const int maxn = 511;

struct Edge {
    int from, to;
	ll cap, flow, cost;
    Edge(int u, int v, ll c, ll f, ll w):from(u),to(v),cap(c),flow(f),cost(w)
    {}
};

struct MCMF {
    int n, m;
    int src, target;
    vector<Edge> edges;
    vector<int> G[maxn];
    int inq[maxn];
    ll d[maxn];
    int p[maxn];
    ll a[maxn];

    MCMF() {}

    void init(int n=maxn) {
        this->n = n;
        for(int i = 0; i < n; i++) G[i].clear();
        edges.clear();
    }

    void addedge(int from, int to, ll cap, ll cost) {
        edges.push_back(Edge(from, to, cap, 0, cost));
        edges.push_back(Edge(to, from, 0, 0, -cost));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool SPFA(int s, int t, ll &flow, ll &cost) {
        for(int i = 0; i < n; i++) d[i] = INF;
        memset(inq, 0, sizeof(inq));
        d[s] = 0; inq[s] = 1; p[s] = 0; a[s] = INF;

        queue<int> Q;
        Q.push(s);
        while(!Q.empty()) {
            int u = Q.front(); Q.pop();
            inq[u] = 0;
            for(int i = 0; i < (int) G[u].size(); i++) {
                Edge& e = edges[G[u][i]];
                if(e.cap > e.flow && d[e.to] > d[u] + e.cost) {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if(!inq[e.to]) { Q.push(e.to); inq[e.to] = 1; }
                }
            }
        }
        if(d[t] == INF) return false;
        flow += a[t];
        cost += d[t] * a[t];
        for(int u = t; u != s; u = edges[p[u]].from) {
        		edges[p[u]].flow += a[t];
        		edges[p[u]^1].flow -= a[t];
		}
        return true;
    }

    ll mincostMaxflow(ll &cost) {
        ll flow = 0;
		cost = 0;
        while(SPFA(src, target, flow, cost));
        return flow;
    }
};

MCMF mf;
char st[maxn];
char g[maxn];

int main() {
	mf.init();
	int n, i, x, j, k, m;
	scanf("%d", &n);
	scanf("%s", st + 1);
	scanf("%d", &m);

	for (i = 1; i <= m; ++i) {
		scanf("%s%d", g, &x);
		int len = strlen(g);
		for (j = 1; j <= n; ++j) {
			int l = j, r = j + len - 1;
			if (r > n) break;
			bool valid = true;
			for (k = l; k <= r; ++k) {
				if (g[k-l] != st[k]) {
					valid = false;
					break;
				}
			}
			if (valid) {
				mf.addedge(l, r + 1, 1, -x);
			}
		}
	}

	scanf("%d", &x);
	mf.src = 0, mf.target = n + 1;
	for (i = 0 ; i <= n; ++i) {
		mf.addedge(i, i+1, x, 0);
	}

	ll cost = 0;
	mf.mincostMaxflow(cost);
	printf("%I64d\n", -cost);
	return 0;
}


#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int inf=0x3f3f3f3f;
const int N=2e3+10,M=1e6+10;
int n,m,x,s,t,d[N],st[N],vis[N],cost;	char str[N],a[N];
int head[N],nex[M],to[M],w[M],flow[M],tot=1;
inline void ade(int a,int b,int c,int d){
	to[++tot]=b; nex[tot]=head[a]; w[tot]=d; flow[tot]=c; head[a]=tot;
}
inline void add(int a,int b,int c,int d){ade(a,b,c,d);	ade(b,a,0,-d);}
inline int spfa(){
	queue<int> q; q.push(s); memset(st,0,sizeof st); memset(d,inf,sizeof d); d[s]=0;
	while(q.size()){
		int u=q.front();	q.pop();	vis[u]=0;
		for(int i=head[u];i;i=nex[i]){
			if(flow[i]&&d[to[i]]>d[u]+w[i]){
				d[to[i]]=d[u]+w[i];
				if(!vis[to[i]])	q.push(to[i]),vis[to[i]]=1;
			}
		}
	}
	return d[t]<inf;
}
int dfs(int x,int f){
	if(x==t)	return cost-=d[t]*f,f;
	int fl=0;	st[x]=1;
	for(int i=head[x];i&&f;i=nex[i]){
		if(!st[to[i]]&&flow[i]&&d[to[i]]==d[x]+w[i]){
			int mi=dfs(to[i],min(flow[i],f));
			flow[i]-=mi,flow[i^1]+=mi,fl+=mi,f-=mi;
		}
	}
	return fl;
}
signed main(){
	cin>>n;	scanf("%s",str+1); cin>>m;	t=n+1;
	for(int i=1,p,len;i<=m;i++){
		scanf("%s %d",a+1,&p); len=strlen(a+1);
		for(int j=1,ok;j<=n+1-len;j++){
			ok=1;
			for(int l1=1,l2=j;l1<=len&&ok;l1++,l2++)	if(a[l1]!=str[l2])	ok=0;
			if(ok)	add(j,j+len,1,-p);
		}
	}
	for(int i=1;i<n;i++)	add(i,i+1,inf,0);
	cin>>x;	add(s,1,x,0); add(n,t,x,0);
	while(spfa())	dfs(s,inf);
	cout<<cost;
	return 0;
}


# include <bits/stdc++.h>
using namespace std;

int N, M, X;
string S;
struct Edge{
  int u, v, cap, cost;
  Edge(){}
  Edge(int _u, int _v, int _cap, int _cost) {
    u = _u;
    v = _v;
    cap = _cap;
    cost = _cost;
  }
};

vector<Edge> edges;
int dist[505], par[505];

int bellmanFord() {
  dist[0] = 0;
  for(int i=1; i<=N; i++) dist[i] = 1e9;

  bool ok = 0;
  do {
    ok = 0;
    for(int i=0; i<edges.size(); i++) {
      Edge e = edges[i];
      if(e.cap == 0) continue;

      int u = e.u;
      int v = e.v;
      if (dist[u] < 1e9 && dist[v] > dist[u] + e.cost) {
        dist[v] = dist[u] + e.cost;
        par[v] = i;
        ok = 1;
      }
    }
  }
  while(ok);

  int cur = N;
  while(cur > 0){
    int pos = par[cur];
    edges[pos].cap--;
    edges[pos^1].cap++;
    cur = edges[pos].u;
  }

  return -dist[N];
}

int main(){

  ios_base :: sync_with_stdio(false);

  cin >> N >> S >> M;
  for(int i=0; i<M; i++){
    string T;
    cin >> T;

    int cost;
    cin >> cost;
    cost = -cost;

    for(int j=0; j+T.size() <= N; j++){
      if(S.substr(j, T.size()) == T){
        edges.emplace_back(j, j+T.size(), 1, cost);
        edges.emplace_back(j+T.size(), j, 0, -cost);
      }
    }
  }

  cin >> X;
  for(int i=0; i<N; i++){
    edges.emplace_back(i, i+1, X, 0);
    edges.emplace_back(i+1, i, 0, 0);
  }

  int ans = 0;
  for(int i=0; i<X; i++){
    ans += bellmanFord();
  }

  cout << ans << endl;

  return 0;
}


#pragma comment(linker, "/stack:200000000")
#pragma GCC optimize("O3")

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <set>
#include <cmath>
#include <bitset>
#include <iomanip>
#include <queue>
#include <stack>
#include <map>
#include <unordered_map>
#include <unordered_set>
#include <unordered_map>

#define int ll
#define fs first
#define sd second
#define mp make_pair
#define pb push_back
#define sz(x) int((x).size())
#define all(x) begin(x), end(x)
#define OUT(x) { cout << x; exit(0); }
//#define resize do_not_use_resize
using namespace std;
typedef double db;
typedef long long ll;
typedef vector<int> vi;
typedef pair<int, int> pii;
const db eps = 1e-9;
const db pi = acos(-1.0);
const db dinf = 1e250;
const ll INF = (ll)(2e18);
const int inf = (int)(1e9 + 7);
const int mod = 1e9 + 7;
const int MAXN = 2*1e5 + 5;
//------------------------------------------//

int n, x;
struct edge {
  int fr, to, cap, cost, flow;
};

vector<edge> ed;

void add_ed(int fr, int to, int cap, int cost) {
  ed.pb({fr, to, cap, cost, 0});
  ed.pb({to, fr, 0, -cost, 0});
}

vector<int> d, pr, minfl;
int s, t;

int fb() {
  d[s] = 0;
  bool fl = 1;
  while (fl) {
    fl = 0;
    for (int i = 0; i < ed.size(); ++i) {
      int fr = ed[i].fr, to = ed[i].to;
      int c = ed[i].cost;
      if (d[fr] != inf && d[fr] + c < d[to] && ed[i].cap > ed[i].flow) {
        d[to] = d[fr] + c;
        pr[to] = i;
        minfl[to] = min(minfl[fr], ed[i].cap - ed[i].flow);
        fl = 1;
      }
    }
  }
  if (d[t] == inf)
    return inf;
  return d[t] * min(minfl[t], x);
}

int32_t main()
{
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(10);
  cin.tie(0);

  //--------------------------------//

  cin >> n;
  string str; cin >> str;
  int m; cin >> m;
  vector<string> w(m);
  vector<int> p(m);
  for (int i = 0; i < m; ++i) {
    cin >> w[i] >> p[i];
  }
  cin >> x;

  for (int i = 0; i < n+1; ++i) {
    add_ed(i, i + 1, inf, 0);
  }

  for (int i = 0; i < m; ++i) {
    string st = w[i] + str;
    int sz = st.size();
    vector<int> z(sz, 0);
    int l = 0, r = 0;
    for (int j = 1; j < sz; ++j) {
      if (j <= r) z[j] = min(z[j - l], r - j + 1);
      for (; j + z[j] < sz && st[z[j]] == st[j + z[j]]; ++z[j]);
      if (j + z[j] - 1 > r) {
        l = j;
        r = j + z[j] - 1;
      }
    }
    int szw = w[i].size();
    for (int j = szw; j < sz; ++j) {
      if (z[j] >= szw) {
        add_ed(j - szw + 1, j + 1, 1, -p[i]);
      }
    }
  }
  n += 2;
  s = 0, t = n - 1;
  int ans = 0;
  while (x > 0) {
    d.assign(n, inf);
    pr.assign(n, -1);
    minfl.assign(n, inf);
    int a = fb();
    if (a == inf) break;
    ans += a;
    x -= minfl[t];
    int v = t;
    while (true) {
      if (v == s) break;
      ed[pr[v]].flow += minfl[t];
      ed[pr[v] ^ 1].flow -= minfl[t];
      v = ed[pr[v]].fr;
    }
  }
  cout << -ans << endl;
  return 0;
}

/* Wed Nov 13 2019 23:38:06 GMT+0300 (MSK) */

/* Thu Nov 21 2019 18:31:49 GMT+0300 (MSK) */


#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <complex>

using namespace std;

#pragma GCC optimize("Ofast")
#pragma GCC optimization("unroll-loops, no-stack-protector")
#pragma GCC target("avx,avx2,fma")

class min_cost_flow {
public:

	struct edge_node {
		int to;
		int capacity, flow;
		int cost;
		int reverse_id;
	};

	int VERYBIG = 2E9;
	bool min_cost_needed;			// whether min cost calculation is needed
	int n, f, mf, totalcost;
	int s, t;		// source and sink
	vector<vector<edge_node>> adj;
	vector<int> pp, ppid;

	min_cost_flow(int nn, int start, int terminal) {		// initialize network with n nodes, starting from 0
		n = nn;
		s = start;
		t = terminal;

		adj.clear();
		adj.resize(nn);
	}

	void add_path(int a, int b, int forward_capacity, int backward_capacity = 0, int forward_cost = 0, int backward_cost = 0) {	// one directional
		int ida = adj[a].size(), idb = adj[b].size();
		adj[a].push_back({ b, forward_capacity, 0, forward_cost, idb });
		adj[b].push_back({ a, backward_capacity, 0, backward_cost, ida });
	}

	void clear_flow() {		// reset all flow to zero from network
		int i;
		for (i = 0; i < n; i++) {
			for (auto p : adj[i]) p.flow = 0;
		}
	}

	void augment(int v, int maxflow) {
		if (v == s) {
			f = maxflow;		// external variable
		}
		else if (pp[v] != -1) {
			int parent = pp[v], pid = ppid[v], rid = adj[parent][pid].reverse_id;
			int available_flow = adj[parent][pid].capacity - adj[parent][pid].flow;

			if (maxflow < available_flow) augment(parent, maxflow);
			else augment(parent, available_flow);

			adj[parent][pid].flow += f;
			adj[v][rid].flow -= f;

			totalcost += f * (adj[parent][pid].cost - adj[v][rid].cost);
		}
	}

	void solve_flow() {		// returns total cost and mf
		mf = 0;
		totalcost = 0;

		while (1) {
			int i, j, k;
			vector<int> dist, mincost;
			dist.assign(n, VERYBIG);
			dist[s] = 0;

			queue<int> q;
			q.push(s);

			pp.assign(n, -1);		// point back to parents
			ppid.assign(n, -1);		// point back to the edge id in parents

			while (!q.empty()) {
				int u = q.front(), v;
				q.pop();
				for (i = 0; i < adj[u].size(); i++) {
					v = adj[u][i].to;
					if ((adj[u][i].flow < adj[u][i].capacity) && (dist[v] > dist[u] + adj[u][i].cost)) {
						dist[v] = dist[u] + adj[u][i].cost;
						q.push(v);
						pp[v] = u;
						ppid[v] = i;
					}
				}
			}

			f = 0;
			augment(t, VERYBIG);
			if (f == 0) break;
			if (f == VERYBIG) break;
			mf += f;

			//totalcost /= 2;
		}

	}
};

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);

	int n, m, i, j, k, ans, x, INF = 1E5;
	string s;

	cin >> n >> s >> m;
	vector<string> ss(m);
	vector<int> pt(m);
	for (i = 0; i < m; i++) cin >> ss[i] >> pt[i];
	cin >> x;

	min_cost_flow fl(n + 2, 0, n + 1);
	fl.add_path(0, 1, x);
	for (i = 1; i <= n; i++) fl.add_path(i, i + 1, INF);

	for (i = 0; i < m; i++) {
		for (j = 0; j + ss[i].length() <= n; j++) {
			if (s.substr(j, ss[i].length()) == ss[i])
				fl.add_path(i + 1, i + ss[i].length(), 1, 0, -pt[i], pt[i]);
		}
	}

	fl.solve_flow();
	ans = fl.totalcost / -2;

	cout << ans << "\n";

	return 0;
}


#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <math.h>
#include <stdio.h>
#include <string.h>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <functional>
#include <algorithm>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <complex>

using namespace std;

#pragma GCC optimize("Ofast")
#pragma GCC optimization("unroll-loops, no-stack-protector")
#pragma GCC target("avx,avx2,fma")

class min_cost_flow {
public:

	struct edge_node {
		int to;
		int capacity, flow;
		int cost;
		int reverse_id;
	};

	int VERYBIG = 2E9;
	bool min_cost_needed;			// whether min cost calculation is needed
	int n, f, mf, totalcost;
	int s, t;		// source and sink
	vector<vector<edge_node>> adj;
	vector<int> pp, ppid;

	min_cost_flow(int nn, int start, int terminal) {		// initialize network with n nodes, starting from 0
		n = nn;
		s = start;
		t = terminal;

		adj.clear();
		adj.resize(nn);
	}

	void add_path(int a, int b, int forward_capacity, int backward_capacity = 0, int forward_cost = 0, int backward_cost = 0) {	// one directional
		int ida = adj[a].size(), idb = adj[b].size();
		adj[a].push_back({ b, forward_capacity, 0, forward_cost, idb });
		adj[b].push_back({ a, backward_capacity, 0, backward_cost, ida });
	}

	void clear_flow() {		// reset all flow to zero from network
		int i;
		for (i = 0; i < n; i++) {
			for (auto p : adj[i]) p.flow = 0;
		}
	}

	void augment(int v, int maxflow) {
		if (v == s) {
			f = maxflow;		// external variable
		}
		else if (pp[v] != -1) {
			int parent = pp[v], pid = ppid[v], rid = adj[parent][pid].reverse_id;
			int available_flow = adj[parent][pid].capacity - adj[parent][pid].flow;

			if (maxflow < available_flow) augment(parent, maxflow);
			else augment(parent, available_flow);

			adj[parent][pid].flow += f;
			adj[v][rid].flow -= f;

			totalcost += f * (adj[parent][pid].cost - adj[v][rid].cost);
		}
	}

	void solve_flow() {		// returns total cost and mf
		mf = 0;
		totalcost = 0;

		while (1) {
			int i, j, k;
			vector<int> dist, mincost;
			dist.assign(n, VERYBIG);
			dist[s] = 0;

			queue<int> q;
			q.push(s);

			pp.assign(n, -1);		// point back to parents
			ppid.assign(n, -1);		// point back to the edge id in parents

			while (!q.empty()) {
				int u = q.front(), v;
				q.pop();
				for (i = 0; i < adj[u].size(); i++) {
					v = adj[u][i].to;
					if ((adj[u][i].flow < adj[u][i].capacity) && (dist[v] > dist[u] + adj[u][i].cost)) {
						dist[v] = dist[u] + adj[u][i].cost;
						q.push(v);
						pp[v] = u;
						ppid[v] = i;
					}
				}
			}

			f = 0;
			augment(t, VERYBIG);
			if (f == 0) break;
			if (f == VERYBIG) break;
			mf += f;

			//totalcost /= 2;
		}

	}
};

int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);

	int n, m, i, j, k, ans, x, INF = 1E5;
	string s;

	cin >> n >> s >> m;
	vector<string> ss(m);
	vector<int> pt(m);
	for (i = 0; i < m; i++) cin >> ss[i] >> pt[i];
	cin >> x;

	min_cost_flow fl(n + 2, 0, n + 1);
	fl.add_path(0, 1, x);
	for (i = 1; i <= n; i++) fl.add_path(i, i + 1, INF);

	for (i = 0; i < m; i++) {
		for (j = 0; j + ss[i].length() <= n; j++) {
			if (s.substr(j, ss[i].length()) == ss[i])
				fl.add_path(j + 1, j + 1 + ss[i].length(), 1, 0, -pt[i], pt[i]);
		}
	}

	fl.solve_flow();
	ans = fl.totalcost / -2;

	cout << ans << "\n";

	return 0;
}


#pragma comment(linker, "/STACK:268435456")

#include<iostream>
#include<cstdio>

#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<stack>
#include<list>
#include<bitset>

#include<iomanip>
#include<memory.h>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cassert>

using namespace std;

#define forn(i, n) for(int i = 0; i < (int)(n); ++i)
#define for1(i, n) for(int i = 1; i < (int)(n); ++i)
#define nfor(i, n) for(int i = int(n) - 1; i >= 0; --i)
#define fore(i, a, b) for(int i = int(a); i < int(b); ++i)
#define correct(x, y, n, m) (0 <= x && x < n && 0 <= y && y < m)
#define x first
#define y second
#define all(a) a.begin(), a.end()
#define pb push_back
#define mp make_pair
#define sz(v) (int)(v.size())
#define hash archash
#define next arcnext
#define link arclink
#define y0 arcy0
#define y1 arcy1
#define log2 arclog2

template<typename T> inline T abs(T a) { return ((a < 0) ? -a : a); }
template<typename T> inline T sqr(T a) { return a * a; }
template<class T> T gcd(T a, T b) { return a ? gcd(b % a, a) : b; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> T sign(T a) { return a > 0 ? 1 : (a < 0 ? -1 : 0); }

typedef long long li;
typedef unsigned long long uli;
typedef long double ld;
typedef pair <int, int> pt;
typedef vector <int> vi;
typedef vector <vector <int> > vvi;
typedef vector <pair <int, int> > vpt;

const int dx[] = { -1, 0, 1,  0 };
const int dy[] = { 0, 1, 0, -1 };
const int dxK[] = { -1, -1, 0, 1, 1,  1,  0, -1 };
const int dyK[] = { 0,  1, 1, 1, 0, -1, -1, -1 };
const int dxKn[] = { -2, -1, 1, 2,  2,  1, -1, -2 };
const int dyKn[] = { 1,  2, 2, 1, -1, -2, -2, -1 };

const int N = int(1e6) + 9;
const int M = int(1e3) + 9;
const int LOGN = 10;
const int SQN = 350;
const int MOD = int(1e9) + 7;
const int INF = int(1e7) + 100;
const li INF64 = 2e18;
const ld PI = ld(3.1415926535897932384626433832795);
const ld EPS = 1e-9;

int n;

vector<int> g[N];
struct edge {
	int from, to, cost, cap, flow;
	edge(int from, int to, int cost, int cap, int flow) :
		from(from), to(to), cost(cost), cap(cap), flow(flow) {};
};

vector<edge> edges;
void add_edge(int from, int to, int cost, int cap) {
	g[from].push_back((int)edges.size());
	edges.push_back(edge(from, to, cost, cap, 0));
	g[to].push_back((int)edges.size());
	edges.push_back(edge(from, to, -cost, 0, 0));
}

int dist[N];
int p[N];
bool inq[N];

int mcmf(int S, int T, int need) {
	int flow = 0, cost = 0;
	while (flow < need) {
		for (int i = 0; i < n + 1; i++) {
			dist[i] = INF;
			p[i] = -1;
			inq[i] = false;
		}
		queue<int> q;
		q.push(S);
		inq[S] = true;
		dist[S] = 0;
		while (!q.empty()) {
			int u = q.front();
			inq[u] = false;
			q.pop();
			for (int i = 0; i < g[u].size(); i++) {
				int num = g[u][i];
				int to = edges[num].to;
				if (edges[num].flow < edges[num].cap &&
					dist[u] + edges[num].cost < dist[to]) {
					dist[to] = dist[u] + edges[num].cost;
					p[to] = num;
					if (!inq[to]) {
						inq[to] = true;
						q.push(to);
					}
				}
			}
		}

		if (dist[T] >= INF) break;
		int v = T;
		assert(p[v] != -1);
		while (p[v] != -1) {
			int idx = p[v];
			edges[idx].flow++;
			edges[idx ^ 1].flow--;
			cost += edges[idx].cost;
			v = edges[idx].from;
		}
		flow++;
	}
	return cost;
}

void solve() {
	cin >> n;
	string s;
	cin >> s;
	int k;
	cin >> k;

	for (int i = 0; i < k; i++) {
		string p;
		cin >> p;
		int cost;
		cin >> cost;

		for (int j = 0; j + p.length() - 1 < s.length(); j++) {
			if (s.substr(j, p.length()) == p) {
				add_edge(j, j + p.length(), -cost, 1);
			}
		}
	}

	int need;
	cin >> need;
	for (int i = 0; i + 1 < n + 1; i++) {
		add_edge(i, i + 1, 0, need);
	}

	cout << -mcmf(0, n, need) << endl;
}

int main() {
#if _DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	srand(time(NULL));
	cout << setprecision(10) << fixed;
	cerr << setprecision(10) << fixed;

	solve();
	return 0;

}


#pragma comment(linker, "/STACK:268435456")

#include<iostream>
#include<cstdio>

#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<stack>
#include<list>
#include<bitset>

#include<iomanip>
#include<memory.h>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cassert>

using namespace std;

#define forn(i, n) for(int i = 0; i < (int)(n); ++i)
#define for1(i, n) for(int i = 1; i < (int)(n); ++i)
#define nfor(i, n) for(int i = int(n) - 1; i >= 0; --i)
#define fore(i, a, b) for(int i = int(a); i < int(b); ++i)
#define correct(x, y, n, m) (0 <= x && x < n && 0 <= y && y < m)
#define x first
#define y second
#define all(a) a.begin(), a.end()
#define pb push_back
#define mp make_pair
#define sz(v) (int)(v.size())
#define hash archash
#define next arcnext
#define link arclink
#define y0 arcy0
#define y1 arcy1
#define log2 arclog2

template<typename T> inline T abs(T a) { return ((a < 0) ? -a : a); }
template<typename T> inline T sqr(T a) { return a * a; }
template<class T> T gcd(T a, T b) { return a ? gcd(b % a, a) : b; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> T sign(T a) { return a > 0 ? 1 : (a < 0 ? -1 : 0); }

typedef long long li;
typedef unsigned long long uli;
typedef long double ld;
typedef pair <int, int> pt;
typedef vector <int> vi;
typedef vector <vector <int> > vvi;
typedef vector <pair <int, int> > vpt;

const int dx[] = { -1, 0, 1,  0 };
const int dy[] = { 0, 1, 0, -1 };
const int dxK[] = { -1, -1, 0, 1, 1,  1,  0, -1 };
const int dyK[] = { 0,  1, 1, 1, 0, -1, -1, -1 };
const int dxKn[] = { -2, -1, 1, 2,  2,  1, -1, -2 };
const int dyKn[] = { 1,  2, 2, 1, -1, -2, -2, -1 };

const int N = int(1e6) + 9;
const int M = int(1e3) + 9;
const int LOGN = 10;
const int SQN = 350;
const int MOD = int(1e9) + 7;
const int INF = int(1e7) + 100;
const li INF64 = 2e18;
const ld PI = ld(3.1415926535897932384626433832795);
const ld EPS = 1e-9;

int n;

vector<int> g[N];
struct edge {
	int from, to, cost, cap, flow;
	edge(int from, int to, int cost, int cap, int flow) :
		from(from), to(to), cost(cost), cap(cap), flow(flow) {};
};

vector<edge> edges;
void add_edge(int from, int to, int cost, int cap) {
	g[from].push_back((int)edges.size());
	edges.push_back(edge(from, to, cost, cap, 0));
	g[to].push_back((int)edges.size());
	edges.push_back(edge(to, from, -cost, 0, 0));
}

int dist[N];
int p[N];
bool inq[N];

int mcmf(int S, int T, int need) {
	int flow = 0, cost = 0;
	while (flow < need) {
		for (int i = 0; i < n + 1; i++) {
			dist[i] = INF;
			p[i] = -1;
			inq[i] = false;
		}
		queue<int> q;
		q.push(S);
		inq[S] = true;
		dist[S] = 0;
		while (!q.empty()) {
			int u = q.front();
			inq[u] = false;
			q.pop();
			for (int i = 0; i < g[u].size(); i++) {
				int num = g[u][i];
				int to = edges[num].to;
				if (edges[num].flow < edges[num].cap &&
					dist[u] + edges[num].cost < dist[to]) {
					dist[to] = dist[u] + edges[num].cost;
					p[to] = num;
					if (!inq[to]) {
						inq[to] = true;
						q.push(to);
					}
				}
			}
		}

		if (dist[T] >= INF) break;
		int v = T;
		assert(p[v] != -1);
		while (p[v] != -1) {
			int idx = p[v];
			edges[idx].flow++;
			edges[idx ^ 1].flow--;
			cost += edges[idx].cost;
			v = edges[idx].from;
		}
		flow++;
	}
	return cost;
}

void solve() {
	cin >> n;
	string s;
	cin >> s;
	int k;
	cin >> k;

	for (int i = 0; i < k; i++) {
		string p;
		cin >> p;
		int cost;
		cin >> cost;

		for (int j = 0; j + p.length() - 1 < s.length(); j++) {
			if (s.substr(j, p.length()) == p) {
				add_edge(j, j + p.length(), -cost, 1);
			}
		}
	}

	int need;
	cin >> need;
	for (int i = 0; i + 1 < n + 1; i++) {
		add_edge(i, i + 1, 0, need);
	}

	cout << -mcmf(0, n, need) << endl;
}

int main() {
#if _DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	srand(time(NULL));
	cout << setprecision(10) << fixed;
	cerr << setprecision(10) << fixed;

	solve();
	return 0;

}


#pragma comment(linker, "/STACK:268435456")

#include<iostream>
#include<cstdio>

#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<stack>
#include<list>
#include<bitset>

#include<iomanip>
#include<memory.h>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cassert>

using namespace std;

#define forn(i, n) for(int i = 0; i < (int)(n); ++i)
#define for1(i, n) for(int i = 1; i < (int)(n); ++i)
#define nfor(i, n) for(int i = int(n) - 1; i >= 0; --i)
#define fore(i, a, b) for(int i = int(a); i < int(b); ++i)
#define correct(x, y, n, m) (0 <= x && x < n && 0 <= y && y < m)
#define x first
#define y second
#define all(a) a.begin(), a.end()
#define pb push_back
#define mp make_pair
#define sz(v) (int)(v.size())
#define hash archash
#define next arcnext
#define link arclink
#define y0 arcy0
#define y1 arcy1
#define log2 arclog2

template<typename T> inline T abs(T a) { return ((a < 0) ? -a : a); }
template<typename T> inline T sqr(T a) { return a * a; }
template<class T> T gcd(T a, T b) { return a ? gcd(b % a, a) : b; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> T sign(T a) { return a > 0 ? 1 : (a < 0 ? -1 : 0); }

typedef long long li;
typedef unsigned long long uli;
typedef long double ld;
typedef pair <int, int> pt;
typedef vector <int> vi;
typedef vector <vector <int> > vvi;
typedef vector <pair <int, int> > vpt;

const int dx[] = { -1, 0, 1,  0 };
const int dy[] = { 0, 1, 0, -1 };
const int dxK[] = { -1, -1, 0, 1, 1,  1,  0, -1 };
const int dyK[] = { 0,  1, 1, 1, 0, -1, -1, -1 };
const int dxKn[] = { -2, -1, 1, 2,  2,  1, -1, -2 };
const int dyKn[] = { 1,  2, 2, 1, -1, -2, -2, -1 };

const int N = int(1e6) + 9;
const int M = int(1e3) + 9;
const int LOGN = 10;
const int SQN = 350;
const int MOD = int(1e9) + 7;
const int INF = int(1e7) + 100;
const li INF64 = 2e18;
const ld PI = ld(3.1415926535897932384626433832795);
const ld EPS = 1e-9;

vector<int> l[N];
vector<int> r[N];
int x[N];
int y[N];

int le[N];
int re[N];
int co[N];
int n;

vector<int> g[N];
struct edge {
	int from, to, cost, cap, flow;
	edge(int from, int to, int cost, int cap, int flow) :
		from(from), to(to), cost(cost), cap(cap), flow(flow) {};
};

vector<edge> edges;
void add_edge(int from, int to, int cost, int cap) {
	g[from].push_back((int)edges.size());
	edges.push_back(edge(from, to, cost, cap, 0));
	g[to].push_back((int)edges.size());
	edges.push_back(edge(from, to, -cost, 0, 0));
}

int dist[N];
int p[N];
bool inq[N];
int f[N];

int mcmf(int S, int T, int need) {
	int flow = 0, cost = 0;
	while (flow < need) {
		for (int i = 0; i < n + 1; i++) {
			dist[i] = INF;
			p[i] = -1;
			f[i] = 0;
			inq[i] = false;
		}
		queue<int> q;
		q.push(S);
		inq[S] = true;
		dist[S] = 0;
		f[S] = INF;
		while (!q.empty()) {
			int u = q.front();
			inq[u] = false;
			q.pop();
			for (int i = 0; i < g[u].size(); i++) {
				int num = g[u][i];
				int to = edges[num].to;
				if (edges[num].flow < edges[num].cap &&
					dist[u] + edges[num].cost < dist[to]) {
					dist[to] = dist[u] + edges[num].cost;
					f[to] = min(f[u], edges[num].cap - edges[num].flow);
					p[to] = num;
					if (!inq[to]) {
						inq[to] = true; q.push(to);
					}
				}
			}
		}

		if (dist[T] >= INF) break;
		int v = T;
		while (p[v] != -1) {
			int idx = p[v];
			edges[idx].flow++;
			edges[idx ^ 1].flow--;
			cost += edges[idx].cost;
			v = edges[idx].from;
		}
		flow++;
	}
	return cost;
}

void solve() {
	cin >> n;
	string s;
	cin >> s;
	int k;
	cin >> k;

	int sum = 0;
	int num = 0;

	for (int i = 0; i < k; i++) {
		string p;
		cin >> p;
		int cost;
		cin >> cost;

		for (int j = 0; j + p.length() - 1 < s.length(); j++) {
			if (s.substr(j, p.length()) == p) {
				for (int w = j; w < j + p.length(); w++) {
					x[w]++;
				}
				add_edge(j, j + p.length(), -cost, 1);
				sum += cost;
			}
		}
	}

	int need;
	cin >> need;
	for (int i = 0; i + 1 < n + 1; i++) {
		add_edge(i, i + 1, 0, need);
	}

	cout << -mcmf(0, n, need) << endl;
}

int main() {
#if _DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	srand(time(NULL));
	cout << setprecision(10) << fixed;
	cerr << setprecision(10) << fixed;

	solve();

	return 0;

}


#pragma comment(linker, "/STACK:268435456")

#include<iostream>
#include<cstdio>

#include<string>
#include<vector>
#include<set>
#include<map>
#include<queue>
#include<deque>
#include<stack>
#include<list>
#include<bitset>

#include<iomanip>
#include<memory.h>
#include<algorithm>
#include<cstring>
#include<ctime>
#include<cmath>
#include<cassert>

using namespace std;

#define forn(i, n) for(int i = 0; i < (int)(n); ++i)
#define for1(i, n) for(int i = 1; i < (int)(n); ++i)
#define nfor(i, n) for(int i = int(n) - 1; i >= 0; --i)
#define fore(i, a, b) for(int i = int(a); i < int(b); ++i)
#define correct(x, y, n, m) (0 <= x && x < n && 0 <= y && y < m)
#define x first
#define y second
#define all(a) a.begin(), a.end()
#define pb push_back
#define mp make_pair
#define sz(v) (int)(v.size())
#define hash archash
#define next arcnext
#define link arclink
#define y0 arcy0
#define y1 arcy1
#define log2 arclog2

template<typename T> inline T abs(T a) { return ((a < 0) ? -a : a); }
template<typename T> inline T sqr(T a) { return a * a; }
template<class T> T gcd(T a, T b) { return a ? gcd(b % a, a) : b; }
template<class T> T lcm(T a, T b) { return a / gcd(a, b) * b; }
template<class T> T sign(T a) { return a > 0 ? 1 : (a < 0 ? -1 : 0); }

typedef long long li;
typedef unsigned long long uli;
typedef long double ld;
typedef pair <int, int> pt;
typedef vector <int> vi;
typedef vector <vector <int> > vvi;
typedef vector <pair <int, int> > vpt;

const int dx[] = { -1, 0, 1,  0 };
const int dy[] = { 0, 1, 0, -1 };
const int dxK[] = { -1, -1, 0, 1, 1,  1,  0, -1 };
const int dyK[] = { 0,  1, 1, 1, 0, -1, -1, -1 };
const int dxKn[] = { -2, -1, 1, 2,  2,  1, -1, -2 };
const int dyKn[] = { 1,  2, 2, 1, -1, -2, -2, -1 };

const int N = int(1e6) + 9;
const int M = int(1e3) + 9;
const int LOGN = 10;
const int SQN = 350;
const int MOD = int(1e9) + 7;
const int INF = int(1e7) + 100;
const li INF64 = 2e18;
const ld PI = ld(3.1415926535897932384626433832795);
const ld EPS = 1e-9;

vector<int> l[N];
vector<int> r[N];
int x[N];
int y[N];

int le[N];
int re[N];
int co[N];
int n;

vector<int> g[N];
struct edge {
	int from, to, cost, cap, flow;
	edge(int from, int to, int cost, int cap, int flow) :
		from(from), to(to), cost(cost), cap(cap), flow(flow) {};
};

vector<edge> edges;
void add_edge(int from, int to, int cost, int cap) {
	g[from].push_back((int)edges.size());
	edges.push_back(edge(from, to, cost, cap, 0));
	g[to].push_back((int)edges.size());
	edges.push_back(edge(from, to, -cost, 0, 0));
}

int dist[N];
int p[N];
bool inq[N];

int mcmf(int S, int T, int need) {
	int flow = 0, cost = 0;
	while (flow < need) {
		for (int i = 0; i < n + 1; i++) {
			dist[i] = INF;
			p[i] = -1;
			inq[i] = false;
		}
		queue<int> q;
		q.push(S);
		inq[S] = true;
		dist[S] = 0;
		while (!q.empty()) {
			int u = q.front();
			inq[u] = false;
			q.pop();
			for (int i = 0; i < g[u].size(); i++) {
				int num = g[u][i];
				int to = edges[num].to;
				if (edges[num].flow < edges[num].cap &&
					dist[u] + edges[num].cost < dist[to]) {
					dist[to] = dist[u] + edges[num].cost;
					p[to] = num;
					q.push(to);
				}
			}
		}

		if (dist[T] >= INF) break;
		int v = T;
		while (p[v] != -1) {
			int idx = p[v];
			edges[idx].flow++;
			edges[idx ^ 1].flow--;
			cost += edges[idx].cost;
			v = edges[idx].from;
		}
		flow++;
	}
	return cost;
}

void solve() {
	cin >> n;
	string s;
	cin >> s;
	int k;
	cin >> k;

	int sum = 0;
	int num = 0;

	for (int i = 0; i < k; i++) {
		string p;
		cin >> p;
		int cost;
		cin >> cost;

		for (int j = 0; j + p.length() - 1 < s.length(); j++) {
			if (s.substr(j, p.length()) == p) {
				for (int w = j; w < j + p.length(); w++) {
					x[w]++;
				}
				add_edge(j, j + p.length(), -cost, 1);
				sum += cost;
			}
		}
	}

	int need;
	cin >> need;
	for (int i = 0; i + 1 < n + 1; i++) {
		add_edge(i, i + 1, 0, need);
	}

	cout << -mcmf(0, n, need) << endl;
}

int main() {
#if _DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	srand(time(NULL));
	cout << setprecision(10) << fixed;
	cerr << setprecision(10) << fixed;

	solve();
	return 0;

}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <list>
#include <set>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <ctime>
#include <queue>
#include <map>
#include <cstring>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef bool bl;
typedef pair<bl, bl> pbl;
typedef pair<ld, ld> pld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define mp make_pair
#define ft first
#define sd second
#define forn(i, y, x) for(int i = y; i < x; i++)
#define ford(i, y, x) for(int i = y; i >= x; i--)
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define error exit(1)
#define sqr(x) ((x)*(x))
#define DEBUG
const ll mod = (ll)1e9 + 7;
const int inf = (int)1e9;
const ll INF = (ll)1e18;
const int base = 1000 * 1000 * 1000;
const int maxn = 505;
const ld pi = acosl(-1.0);
const ld eps = 1e-9;

struct edge
{
	int to, c, f, w, rev;
};

vector<edge> g[maxn];
int cost = 0;

void add(int x, int y, int c, int w)
{
	edge fe = { y, c, 0, w, sz(g[y]) };
	edge be = { x, 0, 0, -w, sz(g[x]) };
	g[x].push_back(fe);
	g[y].push_back(be);
}

bool min_cost_max_flow(int s, int t)
{
	vector<int> d(maxn, inf);
	d[s] = 0;
	vector<int> mf(maxn, 0);
	mf[s] = inf;
	vector<int> p(maxn, -1);
	p[s] = s;
	vector<int> e(maxn, -1);
	vector<int> id(maxn, 0);
	deque<int> q;
	q.push_back(s);
	while (!q.empty()){
		int v = q.front(); q.pop_front();
		id[v] = 2;
		forn(i, 0, sz(g[v])){
			edge to = g[v][i];
			int f = to.c - to.f;
			int nwd = d[v] + to.w;
			if (f > 0 && nwd < d[to.to]){
				d[to.to] = nwd;
				if (id[to.to] == 0) q.push_back(to.to);
				else if (id[to.to] == 2) q.push_front(to.to);
				id[to.to] = 1;
				mf[to.to] = min(mf[v], f);
				p[to.to] = v;
				e[to.to] = i;
			}
		}
	}
	if (p[t] == -1) return false;
	int del = mf[t];
	while (p[t] != t){
		g[p[t]][e[t]].f += del;
		g[t][g[p[t]][e[t]].rev].f -= del;
		cost += g[p[t]][e[t]].w;
		t = p[t];
	}
	return true;
}

void solve()
{
	int n, m, x;
	string s;
	cin >> n >> s >> m;
	vector<string> t(n);
	vector<int> p(n);
	forn(i, 0, m) cin >> t[i] >> p[i];
	cin >> x;
	forn(i, 0, n){
		add(i, i + 1, x, 0);
		forn(j, 0, m) if (i + sz(t[j]) <= n){
			bool ok = true;
			forn(k, 0, sz(t[j])) if (t[j][k] != s[i + k]){
				ok = false;
				break;
			}
			if (ok) add(i, i + sz(t[j]), 1, -p[j]);
		}
	}
	add(n + 1, 0, x, 0);
	int ans = 0;
	while (min_cost_max_flow(n + 1, n)){
		ans -= cost;
		cost = 0;
	}
	cout << ans;
}

int main()
{
#ifdef _DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	solve();
	return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <list>
#include <set>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <string>
#include <cmath>
#include <algorithm>
#include <stack>
#include <ctime>
#include <queue>
#include <map>
#include <cstring>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef bool bl;
typedef pair<bl, bl> pbl;
typedef pair<ld, ld> pld;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
#define mp make_pair
#define ft first
#define sd second
#define forn(i, y, x) for(int i = y; i < x; i++)
#define ford(i, y, x) for(int i = y; i >= x; i--)
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
#define error exit(1)
#define sqr(x) ((x)*(x))
#define DEBUG
const ll mod = (ll)1e9 + 7;
const int inf = (int)1e9;
const ll INF = (ll)1e18;
const int base = 1000 * 1000 * 1000;
const int maxn = 10;//505;
const ld pi = acosl(-1.0);
const ld eps = 1e-9;

struct edge
{
	int to, c, f, w, rev;
};

vector<edge> g[maxn];
int cost = 0;

void add(int x, int y, int c, int w)
{
	edge fe = { y, c, 0, w, sz(g[y]) };
	edge be = { x, 0, 0, -w, sz(g[x]) };
	g[x].push_back(fe);
	g[y].push_back(be);
}

bool min_cost_max_flow(int s, int t)
{
	vector<int> d(maxn, inf);
	d[s] = 0;
	vector<int> mf(maxn, 0);
	mf[s] = inf;
	vector<int> p(maxn, -1);
	p[s] = s;
	vector<int> e(maxn, -1);
	vector<int> id(maxn, 0);
	deque<int> q;
	q.push_back(s);
	while (!q.empty()){
		int v = q.front(); q.pop_front();
		id[v] = 2;
		forn(i, 0, sz(g[v])){
			edge to = g[v][i];
			int f = to.c - to.f;
			int nwd = d[v] + to.w;
			if (f > 0 && nwd < d[to.to]){
				d[to.to] = nwd;
				if (id[to.to] == 0) q.push_back(to.to);
				else if (id[to.to] == 2) q.push_front(to.to);
				id[to.to] = 1;
				mf[to.to] = min(mf[v], f);
				p[to.to] = v;
				e[to.to] = i;
			}
		}
	}
	if (p[t] == -1) return false;
	int del = mf[t];
	while (p[t] != t){
		g[p[t]][e[t]].f += del;
		g[t][g[p[t]][e[t]].rev].f -= del;
		cost += g[p[t]][e[t]].w;
		t = p[t];
	}
	return true;
}

void solve()
{
	int n, m, x;
	string s;
	cin >> n >> s >> m;
	vector<string> t(n);
	vector<int> p(n);
	forn(i, 0, m) cin >> t[i] >> p[i];
	cin >> x;
	forn(i, 0, n){
		add(i, i + 1, x, 0);
		forn(j, 0, m) if (i + sz(t[j]) <= n){
			bool ok = true;
			forn(k, 0, sz(t[j])) if (t[j][k] != s[i + k]){
				ok = false;
				break;
			}
			if (ok) add(i, i + sz(t[j]), 1, -p[j]);
		}
	}
	add(n + 1, 0, x, 0);
	int ans = 0;
	while (min_cost_max_flow(n + 1, n)){
		ans -= cost;
		cost = 0;
	}
	cout << ans;
}

int main()
{
#ifdef _DEBUG
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	solve();
	return 0;
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Numerics;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    public void Solve()
    {
        int n = ReadInt();
        string s = ReadToken();

        var o = Init<List<Tuple<int, int>>>(n);
        for (int m = ReadInt(); m > 0; m--)
        {
            string t = ReadToken();
            int p = ReadInt();
            for (int i = t.Length - 1; i < n; i++)
                if (s.Substring(i - t.Length + 1, t.Length) == t)
                    o[i].Add(Tuple.Create(i - t.Length + 1, p));
        }

        int ans = 0;
        for (int m = ReadInt(); m > 0; m--)
        {
            var dp = Enumerable.Repeat(-1, n + 1).ToArray();
            dp[0] = 0;
            var path = new int[n + 1];
            for (int i = 0; i < n; i++)
            {
                if (dp[i + 1] < dp[i])
                {
                    dp[i + 1] = dp[i];
                    path[i + 1] = -1;
                }
                for (int j = 0; j < o[i].Count; j++)
                {
                    if (dp[i + 1] < dp[o[i][j].Item1] + o[i][j].Item2)
                    {
                        dp[i + 1] = dp[o[i][j].Item1] + o[i][j].Item2;
                        path[i + 1] = j;
                    }
                }
            }

            ans += dp[n];
            int x = n;
            while (x > 0)
            {
                if (path[x] == -1)
                    x--;
                else
                {
                    int nx = o[x - 1][path[x]].Item1;
                    o[x - 1].RemoveAt(path[x]);
                    x = nx;
                }
            }
        }

        Write(ans);
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("input.txt");
        //writer = new StreamWriter("output.txt");
#endif
        try
        {
            new Solver().Solve();
            //var thread = new Thread(new Solver().Solve, 1024 * 1024 * 128);
            //thread.Start();
            //thread.Join();
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0)currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++)matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++)ret[i][j] = matrix[j][i]; } return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++)lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array)writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++)ret[i] = new T(); return ret; }
    #endregion
}


using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Numerics;

// (づ°ω°)づﾐe★゜・。。・゜゜・。。・゜☆゜・。。・゜゜・。。・゜
public class Solver
{
    class Edge<T>
    {
        public int To, Inv;
        public T Capacity, Cost, Flow;
        public Edge(int to, int inv, T capacity, T cost, T flow)
        {
            To = to;
            Inv = inv;
            Capacity = capacity;
            Cost = cost;
            Flow = flow;
        }
    }

    static void AddEdge(List<Edge<int>>[] g, int from, int to, int capacity, int cost)
    {
        g[from].Add(new Edge<int>(to, g[to].Count, capacity, cost, 0));
        g[to].Add(new Edge<int>(from, g[from].Count - 1, 0, -cost, 0));
    }

    int MinCost(List<Edge<int>>[] g, int source, int sink, int limit)
    {
        const int INF = int.MaxValue / 2;

        int n = g.Length;
        int flow = 0, cost = 0;
        while (flow < limit)
        {
            var id = new int[n];
            var dist = Enumerable.Repeat(INF, n).ToArray();
            var q = new int[n];
            var path = new int[n];
            var epath = new int[n];
            int qh = 0, qt = 0;
            q[qt++] = source;
            dist[source] = 0;
            while (qh != qt)
            {
                int v = q[qh++];
                if (qh == n)
                    qh = 0;
                id[v] = 2;
                for (int i = 0; i < g[v].Count; i++)
                {
                    var r = g[v][i];
                    if (r.Flow < r.Capacity && dist[v] + r.Cost < dist[r.To])
                    {
                        dist[r.To] = dist[v] + r.Cost;
                        if (id[r.To] == 0)
                        {
                            q[qt++] = r.To;
                            if (qt == n)
                                qt = 0;
                        }
                        else if (id[r.To] == 2)
                        {
                            if (--qh == -1)
                                qh = n - 1;
                            q[qh] = r.To;
                        }
                        id[r.To] = 1;
                        path[r.To] = v;
                        epath[r.To] = i;
                    }
                }
            }
            if (dist[sink] == INF)
                break;
            int addflow = limit - flow;
            for (int v = sink; v != source; v = path[v])
            {
                int pv = path[v];
                int pr = epath[v];
                addflow = Math.Min(addflow, g[pv][pr].Capacity - g[pv][pr].Flow);
            }
            for (int v = sink; v != source; v = path[v])
            {
                int pv = path[v];
                int pr = epath[v], r = g[pv][pr].Inv;
                g[pv][pr].Flow += addflow;
                g[v][r].Flow -= addflow;
                cost += g[pv][pr].Cost * addflow;
            }
            flow += addflow;
        }
        return cost;
    }

    public void Solve()
    {
        int n = ReadInt();
        string s = ReadToken();

        var g = Init<List<Edge<int>>>(n + 1);
        for (int i = 0; i < n; i++)
            AddEdge(g, i, i + 1, 1000, 0);

        for (int m = ReadInt(); m > 0; m--)
        {
            string t = ReadToken();
            int p = ReadInt();
            for (int i = 0; i + t.Length <= s.Length; i++)
                if (s.Substring(i, t.Length) == t)
                    AddEdge(g, i, i + t.Length, 1, -p);
        }

        Write(-MinCost(g, 0, n, ReadInt()));
    }

    #region Main

    protected static TextReader reader;
    protected static TextWriter writer;
    static void Main()
    {
#if DEBUG
        reader = new StreamReader("..\\..\\input.txt");
        //reader = new StreamReader(Console.OpenStandardInput());
        writer = Console.Out;
        //writer = new StreamWriter("..\\..\\output.txt");
#else
        reader = new StreamReader(Console.OpenStandardInput());
        writer = new StreamWriter(Console.OpenStandardOutput());
        //reader = new StreamReader("input.txt");
        //writer = new StreamWriter("output.txt");
#endif
        try
        {
            new Solver().Solve();
            //var thread = new Thread(new Solver().Solve, 1024 * 1024 * 128);
            //thread.Start();
            //thread.Join();
        }
        catch (Exception ex)
        {
#if DEBUG
            Console.WriteLine(ex);
#else
            throw;
#endif
        }
        reader.Close();
        writer.Close();
    }

    #endregion

    #region Read / Write
    private static Queue<string> currentLineTokens = new Queue<string>();
    private static string[] ReadAndSplitLine() { return reader.ReadLine().Split(new[] { ' ', '\t', }, StringSplitOptions.RemoveEmptyEntries); }
    public static string ReadToken() { while (currentLineTokens.Count == 0)currentLineTokens = new Queue<string>(ReadAndSplitLine()); return currentLineTokens.Dequeue(); }
    public static int ReadInt() { return int.Parse(ReadToken()); }
    public static long ReadLong() { return long.Parse(ReadToken()); }
    public static double ReadDouble() { return double.Parse(ReadToken(), CultureInfo.InvariantCulture); }
    public static int[] ReadIntArray() { return ReadAndSplitLine().Select(int.Parse).ToArray(); }
    public static long[] ReadLongArray() { return ReadAndSplitLine().Select(long.Parse).ToArray(); }
    public static double[] ReadDoubleArray() { return ReadAndSplitLine().Select(s => double.Parse(s, CultureInfo.InvariantCulture)).ToArray(); }
    public static int[][] ReadIntMatrix(int numberOfRows) { int[][] matrix = new int[numberOfRows][]; for (int i = 0; i < numberOfRows; i++)matrix[i] = ReadIntArray(); return matrix; }
    public static int[][] ReadAndTransposeIntMatrix(int numberOfRows)
    {
        int[][] matrix = ReadIntMatrix(numberOfRows); int[][] ret = new int[matrix[0].Length][];
        for (int i = 0; i < ret.Length; i++) { ret[i] = new int[numberOfRows]; for (int j = 0; j < numberOfRows; j++)ret[i][j] = matrix[j][i]; } return ret;
    }
    public static string[] ReadLines(int quantity) { string[] lines = new string[quantity]; for (int i = 0; i < quantity; i++)lines[i] = reader.ReadLine().Trim(); return lines; }
    public static void WriteArray<T>(IEnumerable<T> array) { writer.WriteLine(string.Join(" ", array)); }
    public static void Write(params object[] array) { WriteArray(array); }
    public static void WriteLines<T>(IEnumerable<T> array) { foreach (var a in array)writer.WriteLine(a); }
    private class SDictionary<TKey, TValue> : Dictionary<TKey, TValue>
    {
        public new TValue this[TKey key]
        {
            get { return ContainsKey(key) ? base[key] : default(TValue); }
            set { base[key] = value; }
        }
    }
    private static T[] Init<T>(int size) where T : new() { var ret = new T[size]; for (int i = 0; i < size; i++)ret[i] = new T(); return ret; }
    #endregion
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;
import java.util.Map.Entry;

public class MinCostFlowBF {

	static class Edge {
		int to, f, cap, cost, rev;

		Edge(int v, int cap, int cost, int rev) {
			this.to = v;
			this.cap = cap;
			this.cost = cost;
			this.rev = rev;
		}
	}

	public static List<Edge>[] createGraph(int n) {
		List<Edge>[] graph = new List[n];
		for (int i = 0; i < n; i++)
			graph[i] = new ArrayList<Edge>();
		return graph;
	}

	public static void addEdge(List<Edge>[] graph, int s, int t, int cap, int cost) {
		graph[s].add(new Edge(t, cap, cost, graph[t].size()));
		graph[t].add(new Edge(s, 0, -cost, graph[s].size() - 1));
	}

	static void bellmanFord(List<Edge>[] graph, int s, int[] dist, int[] prevnode, int[] prevedge, int[] curflow) {
		int n = graph.length;
		Arrays.fill(dist, 0, n, Integer.MAX_VALUE);
		dist[s] = 0;
		curflow[s] = Integer.MAX_VALUE;
		boolean[] inqueue = new boolean[n];
		int[] q = new int[n];
		int qt = 0;
		q[qt++] = s;
		for (int qh = 0; (qh - qt) % n != 0; qh++) {
			int u = q[qh % n];
			inqueue[u] = false;
			for (int i = 0; i < graph[u].size(); i++) {
				Edge e = graph[u].get(i);
				if (e.f >= e.cap)
					continue;
				int v = e.to;
				int ndist = dist[u] + e.cost;
				if (dist[v] > ndist) {
					dist[v] = ndist;
					prevnode[v] = u;
					prevedge[v] = i;
					curflow[v] = Math.min(curflow[u], e.cap - e.f);
					if (!inqueue[v]) {
						inqueue[v] = true;
						q[qt++ % n] = v;
					}
				}
			}
		}
	}

	public static int[] minCostFlow(List<Edge>[] graph, int s, int t, int maxf) {
		int n = graph.length;
		int[] dist = new int[n];
		int[] curflow = new int[n];
		int[] prevedge = new int[n];
		int[] prevnode = new int[n];

		int flow = 0;
		int flowCost = 0;
		while (flow < maxf) {
			bellmanFord(graph, s, dist, prevnode, prevedge, curflow);
			if (dist[t] == Integer.MAX_VALUE)
				break;
			int df = Math.min(curflow[t], maxf - flow);
			flow += df;
			for (int v = t; v != s; v = prevnode[v]) {
				Edge e = graph[prevnode[v]].get(prevedge[v]);
				e.f += df;
				graph[v].get(e.rev).f -= df;
				flowCost += df * e.cost;
			}
		}
		return new int[]{flow, flowCost};
	}

	static String str;
	static int n;
	static int id = 2;
	static final int START = 0;
	static final int END = 1;
	static int in[],out[];
	public static void main(String[] args) throws Throwable
	{
		Scanner sc = new Scanner(System.in);

		n = sc.nextInt();
		List<Edge> G[] = createGraph(2 * n + 5);
		in = new int[n]; out = new int[n];
		str = sc.next();
		for(int i = 0 ; i < n ; ++i)
		{
			in[i] = id++;
			out[i] = id++;
		}

		int m = sc.nextInt();

		ArrayList<String> words = new ArrayList();
		TreeMap<String,Integer> map = new TreeMap();
		for(int i = 0 ; i < m ; ++i)
		{
			String str = sc.next();
			if(map.containsKey(str))
				map.put(str, Math.max(map.get(str), sc.nextInt()));
			else map.put(str, sc.nextInt());
		}
		int cost[] = new int[map.size()];
		int ind = 0;
		for(Entry<String, Integer> x : map.entrySet())
		{
			words.add(x.getKey());
			cost[ind] = x.getValue() * -1;
			ind++;
		}
		m = words.size();
		int x = sc.nextInt();
		for(int i = 0 ; i < n - 1 ; ++i)
		{
			addEdge(G,out[i],in[i + 1],100000,0);
		}
		for(int i = 0 ; i < n ; ++i)
		{
			addEdge(G,in[i],out[i],x,0);
		}
		for(int k = 0 ; k < words.size() ; ++k)
		{
			String s = words.get(k);
			for(int i = 0 ; i < n ; ++i)
			{
				boolean bad = false;
				if(i + s.length() - 1 >= n)
					break;
				for(int j = 0 ; j < s.length() && !bad ; ++j)
				{
					if(s.charAt(j) != str.charAt(i + j))
						bad = true;
				}
				if(!bad)
				{
					addEdge(G,START,in[i],1,0);
					addEdge(G,out[i + s.length() - 1],END,1,cost[k]);
				}
			}
		}
		int ans[] = minCostFlow(G,START,END,Integer.MAX_VALUE);
		System.out.println(-1*ans[1]);
	}

	static class Scanner
	{
		BufferedReader br;
		StringTokenizer st;

		Scanner(InputStream s)  { br = new BufferedReader(new InputStreamReader(s)); }

		String next() throws IOException
		{

			while(st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();

		}
		int nextInt() throws NumberFormatException, IOException { return Integer.parseInt(next()); }
		long nextLong() throws NumberFormatException, IOException { return Long.parseLong(next()); }

	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

public class MinCostFlowBF
{

	static class Edge {
		int to, f, cap, cost, rev;

		Edge(int v, int cap, int cost, int rev) {
			this.to = v;
			this.cap = cap;
			this.cost = cost;
			this.rev = rev;
		}
	}

	public static List<Edge>[] createGraph(int n) {
		List<Edge>[] graph = new List[n];
		for (int i = 0; i < n; i++)
			graph[i] = new ArrayList<Edge>();
		return graph;
	}

	public static void addEdge(List<Edge>[] graph, int s, int t, int cap, int cost) {
		graph[s].add(new Edge(t, cap, cost, graph[t].size()));
		graph[t].add(new Edge(s, 0, -cost, graph[s].size() - 1));
	}

	static void bellmanFord(List<Edge>[] graph, int s, int[] dist, int[] prevnode, int[] prevedge, int[] curflow) {
		int n = graph.length;
		Arrays.fill(dist, 0, n, Integer.MAX_VALUE);
		dist[s] = 0;
		curflow[s] = Integer.MAX_VALUE;
		boolean[] inqueue = new boolean[n];
		int[] q = new int[n];
		int qt = 0;
		q[qt++] = s;
		for (int qh = 0; (qh - qt) % n != 0; qh++) {
			int u = q[qh % n];
			inqueue[u] = false;
			for (int i = 0; i < graph[u].size(); i++) {
				Edge e = graph[u].get(i);
				if (e.f >= e.cap)
					continue;
				int v = e.to;
				int ndist = dist[u] + e.cost;
				if (dist[v] > ndist) {
					dist[v] = ndist;
					prevnode[v] = u;
					prevedge[v] = i;
					curflow[v] = Math.min(curflow[u], e.cap - e.f);
					if (!inqueue[v]) {
						inqueue[v] = true;
						q[qt++ % n] = v;
					}
				}
			}
		}
	}

	public static int[] minCostFlow(List<Edge>[] graph, int s, int t, int maxf) {
		int n = graph.length;
		int[] dist = new int[n];
		int[] curflow = new int[n];
		int[] prevedge = new int[n];
		int[] prevnode = new int[n];

		int flow = 0;
		int flowCost = 0;
		while (flow < maxf) {
			bellmanFord(graph, s, dist, prevnode, prevedge, curflow);
			if (dist[t] == Integer.MAX_VALUE)
				break;
			int df = Math.min(curflow[t], maxf - flow);
			flow += df;
			for (int v = t; v != s; v = prevnode[v]) {
				Edge e = graph[prevnode[v]].get(prevedge[v]);
				e.f += df;
				graph[v].get(e.rev).f -= df;
				flowCost += df * e.cost;
			}
		}
		return new int[]{flow, flowCost};
	}

	static String str;
	static int n;
	static int id = 2;
	static int START = 0;
	static int END = 0;
	static int ind[];
	public static void main(String[] args) throws Throwable
	{
		Scanner sc = new Scanner(System.in);

		n = sc.nextInt();
		List<Edge> G[] = createGraph(n + 2);
		START = n;
		END = n + 1;

		str = sc.next();

		int m = sc.nextInt();
		int cost[] = new int[m];
		ArrayList<String> words = new ArrayList();
		for(int i = 0 ; i < m ; ++i)
		{
			words.add(sc.next());
			cost[i] = -1*sc.nextInt();
		}
		int x = sc.nextInt();
		for(int i = 0 ; i < n - 1 ; ++i)
		{
			addEdge(G,i,i + 1,x,0);
		}
		addEdge(G,START,0,x,0);
		addEdge(G,n - 1,END,x,0);
		for(int k = 0 ; k < words.size() ; ++k)
		{
			String s = words.get(k);
			for(int i = 0 ; i < n ; ++i)
			{
				boolean bad = false;
				if(i + s.length() - 1 >= n)
					break;
				for(int j = 0 ; j < s.length() && !bad ; ++j)
				{
					if(s.charAt(j) != str.charAt(i + j))
						bad = true;
				}
				if(!bad)
				{
					int to = i + s.length() >= n ? END : i + s.length();

					addEdge(G,i,to,1,cost[k]);
				}
			}
		}

		int ans[] = minCostFlow(G,START,END,1000000);
		System.out.println(-1*ans[1]);
	}

	static class Scanner
	{
		BufferedReader br;
		StringTokenizer st;

		Scanner(InputStream s)  { br = new BufferedReader(new InputStreamReader(s)); }

		String next() throws IOException
		{

			while(st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();

		}
		int nextInt() throws NumberFormatException, IOException { return Integer.parseInt(next()); }
		long nextLong() throws NumberFormatException, IOException { return Long.parseLong(next()); }

	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

public class MinCostFlowBF
{

	static class Edge {
		int to, f, cap, cost, rev;

		Edge(int v, int cap, int cost, int rev) {
			this.to = v;
			this.cap = cap;
			this.cost = cost;
			this.rev = rev;
		}
	}

	public static List<Edge>[] createGraph(int n) {
		List<Edge>[] graph = new List[n];
		for (int i = 0; i < n; i++)
			graph[i] = new ArrayList<Edge>();
		return graph;
	}

	public static void addEdge(List<Edge>[] graph, int s, int t, int cap, int cost) {
		graph[s].add(new Edge(t, cap, cost, graph[t].size()));
		graph[t].add(new Edge(s, 0, -cost, graph[s].size() - 1));
	}

	static void bellmanFord(List<Edge>[] graph, int s, int[] dist, int[] prevnode, int[] prevedge, int[] curflow) {
		int n = graph.length;
		Arrays.fill(dist, 0, n, Integer.MAX_VALUE);
		dist[s] = 0;
		curflow[s] = Integer.MAX_VALUE;
		boolean[] inqueue = new boolean[n];
		int[] q = new int[n];
		int qt = 0;
		q[qt++] = s;
		for (int qh = 0; (qh - qt) % n != 0; qh++) {
			int u = q[qh % n];
			inqueue[u] = false;
			for (int i = 0; i < graph[u].size(); i++) {
				Edge e = graph[u].get(i);
				if (e.f >= e.cap)
					continue;
				int v = e.to;
				int ndist = dist[u] + e.cost;
				if (dist[v] > ndist) {
					dist[v] = ndist;
					prevnode[v] = u;
					prevedge[v] = i;
					curflow[v] = Math.min(curflow[u], e.cap - e.f);
					if (!inqueue[v]) {
						inqueue[v] = true;
						q[qt++ % n] = v;
					}
				}
			}
		}
	}

	public static int[] minCostFlow(List<Edge>[] graph, int s, int t, int maxf) {
		int n = graph.length;
		int[] dist = new int[n];
		int[] curflow = new int[n];
		int[] prevedge = new int[n];
		int[] prevnode = new int[n];

		int flow = 0;
		int flowCost = 0;
		while (flow < maxf) {
			bellmanFord(graph, s, dist, prevnode, prevedge, curflow);
			if (dist[t] == Integer.MAX_VALUE)
				break;
			int df = Math.min(curflow[t], maxf - flow);
			flow += df;
			for (int v = t; v != s; v = prevnode[v]) {
				Edge e = graph[prevnode[v]].get(prevedge[v]);
				e.f += df;
				graph[v].get(e.rev).f -= df;
				flowCost += df * e.cost;
			}
		}
		return new int[]{flow, flowCost};
	}

	static String str;
	static int n;
	static int id = 2;
	static int START = 0;
	static int END = 0;
	static int ind[];
	public static void main(String[] args) throws Throwable
	{
		Scanner sc = new Scanner(System.in);

		n = sc.nextInt();
		List<Edge> G[] = createGraph(n + 2);
		START = n;
		END = n + 1;

		str = sc.next();

		int m = sc.nextInt();
		int cost[] = new int[m];
		ArrayList<String> words = new ArrayList();
		for(int i = 0 ; i < m ; ++i)
		{
			words.add(sc.next());
			cost[i] = -1*sc.nextInt();
		}
		int x = sc.nextInt();
		for(int i = 0 ; i < n - 1 ; ++i)
		{
			addEdge(G,i,i + 1,x,0);
		}
		addEdge(G,START,0,x,0);
		addEdge(G,n - 1,END,x,0);
		for(int k = 0 ; k < words.size() ; ++k)
		{
			String s = words.get(k);
			for(int i = 0 ; i < n ; ++i)
			{
				boolean bad = false;
				if(i + s.length() - 1 >= n)
					break;
				for(int j = 0 ; j < s.length() && !bad ; ++j)
				{
					if(s.charAt(j) != str.charAt(i + j))
						bad = true;
				}
				if(!bad)
				{
					int to = i + s.length() >= n ? END : i + s.length();

					addEdge(G,i,to,1,cost[k]);
				}
			}
		}

		int ans[] = minCostFlow(G,START,END,Integer.MAX_VALUE);
		System.out.println(-1*ans[1]);
	}

	static class Scanner
	{
		BufferedReader br;
		StringTokenizer st;

		Scanner(InputStream s)  { br = new BufferedReader(new InputStreamReader(s)); }

		String next() throws IOException
		{

			while(st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();

		}
		int nextInt() throws NumberFormatException, IOException { return Integer.parseInt(next()); }
		long nextLong() throws NumberFormatException, IOException { return Long.parseLong(next()); }

	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

public class MinCostFlowBF {

	static class Edge {
		int to, f, cap, cost, rev;

		Edge(int v, int cap, int cost, int rev) {
			this.to = v;
			this.cap = cap;
			this.cost = cost;
			this.rev = rev;
		}
	}

	public static List<Edge>[] createGraph(int n) {
		List<Edge>[] graph = new List[n];
		for (int i = 0; i < n; i++)
			graph[i] = new ArrayList<Edge>();
		return graph;
	}

	public static void addEdge(List<Edge>[] graph, int s, int t, int cap, int cost) {
		graph[s].add(new Edge(t, cap, cost, graph[t].size()));
		graph[t].add(new Edge(s, 0, -cost, graph[s].size() - 1));
	}

	static void bellmanFord(List<Edge>[] graph, int s, int[] dist, int[] prevnode, int[] prevedge, int[] curflow) {
		int n = graph.length;
		Arrays.fill(dist, 0, n, Integer.MAX_VALUE);
		dist[s] = 0;
		curflow[s] = Integer.MAX_VALUE;
		boolean[] inqueue = new boolean[n];
		int[] q = new int[n];
		int qt = 0;
		q[qt++] = s;
		for (int qh = 0; (qh - qt) % n != 0; qh++) {
			int u = q[qh % n];
			inqueue[u] = false;
			for (int i = 0; i < graph[u].size(); i++) {
				Edge e = graph[u].get(i);
				if (e.f >= e.cap)
					continue;
				int v = e.to;
				int ndist = dist[u] + e.cost;
				if (dist[v] > ndist) {
					dist[v] = ndist;
					prevnode[v] = u;
					prevedge[v] = i;
					curflow[v] = Math.min(curflow[u], e.cap - e.f);
					if (!inqueue[v]) {
						inqueue[v] = true;
						q[qt++ % n] = v;
					}
				}
			}
		}
	}

	public static int[] minCostFlow(List<Edge>[] graph, int s, int t, int maxf) {
		int n = graph.length;
		int[] dist = new int[n];
		int[] curflow = new int[n];
		int[] prevedge = new int[n];
		int[] prevnode = new int[n];

		int flow = 0;
		int flowCost = 0;
		while (flow < maxf) {
			bellmanFord(graph, s, dist, prevnode, prevedge, curflow);
			if (dist[t] == Integer.MAX_VALUE)
				break;
			int df = Math.min(curflow[t], maxf - flow);
			flow += df;
			for (int v = t; v != s; v = prevnode[v]) {
				Edge e = graph[prevnode[v]].get(prevedge[v]);
				e.f += df;
				graph[v].get(e.rev).f -= df;
				flowCost += df * e.cost;
			}
		}
		return new int[]{flow, flowCost};
	}

	static String str;
	static int n;
	static int id = 2;
	static final int START = 0;
	static final int END = 1;
	static int in[],out[];
	public static void main(String[] args) throws Throwable
	{
		Scanner sc = new Scanner(System.in);

		n = sc.nextInt();
		List<Edge> G[] = createGraph(2 * n + 5);
		in = new int[n]; out = new int[n];
		str = sc.next();
		for(int i = 0 ; i < n ; ++i)
		{
			in[i] = id++; out[i] = id++;
		}
		for(int i = 0 ; i < n - 1 ; ++i)
		{
			addEdge(G,out[i],in[i + 1],1 << 29,0);
		}
		int m = sc.nextInt();
		int cost[] = new int[m];
		ArrayList<String> words = new ArrayList();
		for(int i = 0 ; i < m ; ++i)
		{
			words.add(sc.next());
			cost[i] = -1*sc.nextInt();
		}
		int x = sc.nextInt();

		for(int i = 0 ; i < n ; ++i)
		{
			addEdge(G,in[i],out[i],x,0);
		}
		for(int k = 0 ; k < words.size() ; ++k)
		{
			String s = words.get(k);
			for(int i = 0 ; i < n ; ++i)
			{
				boolean bad = false;
				if(i + s.length() - 1 >= n)
					break;
				for(int j = 0 ; j < s.length() && !bad ; ++j)
				{
					if(s.charAt(j) != str.charAt(i + j))
						bad = true;
				}
				if(!bad)
				{
					addEdge(G,START,in[i],1,0);
					addEdge(G,out[i + s.length() - 1],END,1,cost[k]);
				}
			}
		}
		int ans[] = minCostFlow(G,START,END,Integer.MAX_VALUE);
		System.out.println(-1*ans[1]);
	}

	static class Scanner
	{
		BufferedReader br;
		StringTokenizer st;

		Scanner(InputStream s)  { br = new BufferedReader(new InputStreamReader(s)); }

		String next() throws IOException
		{

			while(st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();

		}
		int nextInt() throws NumberFormatException, IOException { return Integer.parseInt(next()); }
		long nextLong() throws NumberFormatException, IOException { return Long.parseLong(next()); }

	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.*;

public class MinCostFlow
{

	static class Edge {
		int to, f, cap, cost, rev;

		Edge(int v, int cap, int cost, int rev) {
			this.to = v;
			this.cap = cap;
			this.cost = cost;
			this.rev = rev;
		}
	}

	public static List<Edge>[] createGraph(int n) {
		List<Edge>[] graph = new List[n];
		for (int i = 0; i < n; i++)
			graph[i] = new ArrayList<Edge>();
		return graph;
	}

	public static void addEdge(List<Edge>[] graph, int s, int t, int cap, int cost) {
		graph[s].add(new Edge(t, cap, cost, graph[t].size()));
		graph[t].add(new Edge(s, 0, -cost, graph[s].size() - 1));
	}

	static void bellmanFord(List<Edge>[] graph, int s, int[] dist, int[] prevnode, int[] prevedge, int[] curflow) {
		int n = graph.length;
		Arrays.fill(dist, 0, n, Integer.MAX_VALUE);
		dist[s] = 0;
		curflow[s] = Integer.MAX_VALUE;
		boolean[] inqueue = new boolean[n];
		int[] q = new int[n];
		int qt = 0;
		q[qt++] = s;
		for (int qh = 0; (qh - qt) % n != 0; qh++) {
			int u = q[qh % n];
			inqueue[u] = false;
			for (int i = 0; i < graph[u].size(); i++) {
				Edge e = graph[u].get(i);
				if (e.f >= e.cap)
					continue;
				int v = e.to;
				int ndist = dist[u] + e.cost;
				if (dist[v] > ndist) {
					dist[v] = ndist;
					prevnode[v] = u;
					prevedge[v] = i;
					curflow[v] = Math.min(curflow[u], e.cap - e.f);
					if (!inqueue[v]) {
						inqueue[v] = true;
						q[qt++ % n] = v;
					}
				}
			}
		}
	}

	public static int[] minCostFlow(List<Edge>[] graph, int s, int t, int maxf) {
		int n = graph.length;
		int[] dist = new int[n];
		int[] curflow = new int[n];
		int[] prevedge = new int[n];
		int[] prevnode = new int[n];

		int flow = 0;
		int flowCost = 0;
		while (flow < maxf) {
			bellmanFord(graph, s, dist, prevnode, prevedge, curflow);
			if (dist[t] == Integer.MAX_VALUE)
				break;
			int df = Math.min(curflow[t], maxf - flow);
			flow += df;
			for (int v = t; v != s; v = prevnode[v]) {
				Edge e = graph[prevnode[v]].get(prevedge[v]);
				e.f += df;
				graph[v].get(e.rev).f -= df;
				flowCost += df * e.cost;
			}
		}
		return new int[]{flow, flowCost};
	}

	static String str;
	static int n;
	static int id = 2;
	static int START = 0;
	static int END = 0;
	static int ind[];
	public static void main(String[] args) throws Throwable
	{
		Scanner sc = new Scanner(System.in);

		n = sc.nextInt();
		List<Edge> G[] = createGraph(n + 2);
		START = n;
		END = n + 1;

		str = sc.next();

		int m = sc.nextInt();
		int cost[] = new int[m];
		ArrayList<String> words = new ArrayList();
		for(int i = 0 ; i < m ; ++i)
		{
			words.add(sc.next());
			cost[i] = -1*sc.nextInt();
		}
		int x = sc.nextInt();
		for(int i = 0 ; i < n - 1 ; ++i)
		{
			addEdge(G,i,i + 1,x,0);
		}
		addEdge(G,START,0,x,0);
		addEdge(G,n - 1,END,x,0);
		for(int k = 0 ; k < words.size() ; ++k)
		{
			String s = words.get(k);
			for(int i = 0 ; i < n ; ++i)
			{
				boolean bad = false;
				if(i + s.length() - 1 >= n)
					break;
				for(int j = 0 ; j < s.length() && !bad ; ++j)
				{
					if(s.charAt(j) != str.charAt(i + j))
						bad = true;
				}
				if(!bad)
				{
					int to = i + s.length() >= n ? END : i + s.length();

					addEdge(G,i,to,1,cost[k]);
				}
			}
		}

		int ans[] = minCostFlow(G,START,END,Integer.MAX_VALUE);
		System.out.println(-1*ans[1]);
	}

	static class Scanner
	{
		BufferedReader br;
		StringTokenizer st;

		Scanner(InputStream s)  { br = new BufferedReader(new InputStreamReader(s)); }

		String next() throws IOException
		{

			while(st == null || !st.hasMoreTokens())
				st = new StringTokenizer(br.readLine());
			return st.nextToken();

		}
		int nextInt() throws NumberFormatException, IOException { return Integer.parseInt(next()); }
		long nextLong() throws NumberFormatException, IOException { return Long.parseLong(next()); }

	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.io.IOException;
import java.util.InputMismatchException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Map;
import java.io.Writer;
import java.io.BufferedReader;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 *
 * @author Niyaz Nigmatullin
 */
public class Main {
    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        FastScanner in = new FastScanner(inputStream);
        FastPrinter out = new FastPrinter(outputStream);
        TaskG solver = new TaskG();
        solver.solve(1, in, out);
        out.close();
    }

    static class TaskG {
        public void solve(int testNumber, FastScanner in, FastPrinter out) {
            in.nextInt();
            String s = in.next();
            int m = in.nextInt();
            Map<String, Integer> all = new HashMap<>();
            for (int i = 0; i < m; i++) {
                String p = in.next();
                int c = in.nextInt();
                Integer got = all.get(p);
                if (got == null || got < c) {
                    got = c;
                }
                all.put(p, got);
            }
            final int X = in.nextInt();
            int n = s.length();
            TaskG.MinCostMaxFlowGraph g = new TaskG.MinCostMaxFlowGraph(n + 1);
            for (int i = 0; i < n; i++) {
                g.addEdge(i, i + 1, X, 0);
            }
            TaskG.Edge[] lastEdge = new TaskG.Edge[n + 1];
            long[] d = new long[n + 1];
            int[] q = new int[n + 2];
            boolean[] inQueue = new boolean[n + 1];
            long ans = 0;
            for (int i = 0; i < n; i++) {
                for (int j = i + 1; j <= n; j++) {
                    String sub = s.substring(i, j);
                    if (!all.containsKey(sub)) continue;
                    int c = all.get(sub);
                    Arrays.fill(d, Long.MAX_VALUE);
                    d[i] = 0;
                    int head = 0;
                    int tail = 0;
                    q[tail++] = i;
                    inQueue[i] = true;
                    while (head != tail) {
                        int v = q[head++];
                        if (head == n + 2) {
                            head = 0;
                        }
                        inQueue[v] = false;
                        for (TaskG.Edge e : g.edges[v]) {
                            if (e.flow < e.cap && d[e.from] != Long.MAX_VALUE && d[e.to] > d[e.from] + e.cost) {
                                d[e.to] = d[e.from] + e.cost;
                                lastEdge[e.to] = e;
                                if (!inQueue[e.to]) {
                                    q[tail++] = e.to;
                                    inQueue[e.to] = true;
                                    if (tail == n + 2) tail = 0;
                                }
                            }
                        }
                    }
                    if (d[j] == Long.MAX_VALUE) continue;
                    long pathLen = -c + d[j];
                    if (pathLen >= 0) {
                        g.addEdge(j, i, 1, -c);
                        continue;
                    }
                    ans += pathLen;
                    for (int v = j; v != i; v = lastEdge[v].from) {
                        lastEdge[v].flow++;
                        lastEdge[v].rev.flow--;
                    }
                    g.addEdge(j, i, 1, 1, -c);
//                for (int v = 0; v <= n; v++) {
//                    for (Edge e : g.edges[v]) {
//                        System.out.println(e.from + " " + e.to + " " + e.flow + " " + e.cap + " " + e.cost);
//                    }
//                }
//                System.out.println("==========================");
                }
            }
            out.println(-ans);
        }

        public static class Edge {
            int from;
            int to;
            public int flow;
            int cap;
            long cost;
            TaskG.Edge rev;

            public Edge(int from, int to, int flow, int cap, long cost) {
                this.from = from;
                this.to = to;
                this.flow = flow;
                this.cap = cap;
                this.cost = cost;
            }

            public String toString() {
                return "Edge [from=" + from + ", to=" + to + ", flow=" + flow
                        + ", cap=" + cap + ", cost=" + cost + "]";
            }

        }

        static class MinCostMaxFlowGraph {
            int n;
            ArrayList<TaskG.Edge>[] edges;

            public MinCostMaxFlowGraph(int n) {
                this.n = n;
                edges = new ArrayList[n];
                for (int i = 0; i < edges.length; i++) {
                    edges[i] = new ArrayList<TaskG.Edge>();
                }
            }

            public TaskG.Edge addEdge(int from, int to, int cap, long cost) {
                TaskG.Edge e1 = new TaskG.Edge(from, to, 0, cap, cost);
                TaskG.Edge e2 = new TaskG.Edge(to, from, 0, 0, -cost);
                e1.rev = e2;
                e2.rev = e1;
                edges[from].add(e1);
                edges[to].add(e2);
                return e1;
            }

            public TaskG.Edge addEdge(int from, int to, int cap, int flow, long cost) {
                TaskG.Edge e1 = new TaskG.Edge(from, to, flow, cap, cost);
                TaskG.Edge e2 = new TaskG.Edge(to, from, -flow, 0, -cost);
                e1.rev = e2;
                e2.rev = e1;
                edges[from].add(e1);
                edges[to].add(e2);
                return e1;
            }

        }

    }

    static class FastScanner extends BufferedReader {
        public FastScanner(InputStream is) {
            super(new InputStreamReader(is));
        }

        public int read() {
            try {
                int ret = super.read();
//            if (isEOF && ret < 0) {
//                throw new InputMismatchException();
//            }
//            isEOF = ret == -1;
                return ret;
            } catch (IOException e) {
                throw new InputMismatchException();
            }
        }

        public String next() {
            StringBuilder sb = new StringBuilder();
            int c = read();
            while (isWhiteSpace(c)) {
                c = read();
            }
            if (c < 0) {
                return null;
            }
            while (c >= 0 && !isWhiteSpace(c)) {
                sb.appendCodePoint(c);
                c = read();
            }
            return sb.toString();
        }

        static boolean isWhiteSpace(int c) {
            return c >= 0 && c <= 32;
        }

        public int nextInt() {
            int c = read();
            while (isWhiteSpace(c)) {
                c = read();
            }
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            int ret = 0;
            while (c >= 0 && !isWhiteSpace(c)) {
                if (c < '0' || c > '9') {
                    throw new NumberFormatException("digit expected " + (char) c
                            + " found");
                }
                ret = ret * 10 + c - '0';
                c = read();
            }
            return ret * sgn;
        }

        public String readLine() {
            try {
                return super.readLine();
            } catch (IOException e) {
                return null;
            }
        }

    }

    static class FastPrinter extends PrintWriter {
        public FastPrinter(OutputStream out) {
            super(out);
        }

        public FastPrinter(Writer out) {
            super(out);
        }

    }
}