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

const int N = 1e6 + 7;
const int A = 28;

int par[N];
int poz[N];
int len[N];
int suf[N];
int h[N];
int T[N][A];
char s[N];
int n, m;
int ov;
int gid = 1;

int gd[N];
int su[N];
int ne[N];
int cost[N];
long long dp[N];

long long wynik = 0;

pair <int, int> fastscan(int v, int a, int l) {
	while(1) {
		if(l <= 0) return {v, 0};
		int w = T[v][s[a] - 'a'];
		if(l < len[w]) return {v, l};
		l -= len[w];
		a += len[w];
		v = w;
	}
}

void pisz(int v) {
	for(int i = 0; i < A; ++i) {
		int w = T[v][i];
		if(w) {
			cout << v << ' ' << w << " - ";
			for(int j = poz[w]; j < poz[w] + len[w]; ++j) cout << s[j];
			cout << " - " << poz[w] << ' ' << len[w] << endl;
			pisz(w);
		}
	}
}

void dfs1(int v) {
	for(int i = 0; i < A; ++i) {
		int w = T[v][i];
		if(w) {
			dfs1(w);
			dp[v] += dp[w];
		}
	}
}

void dfs2(int v) {
	for(int i = 0; i < A; ++i) {
		int w = T[v][i];
		if(w) {
			int a = poz[w];
			int b = a + len[w] - 1;
			if(su[b] - su[a - 1] == 0) {
				wynik = max(wynik, dp[w] * h[w]);
				dfs2(w);
			}
			else {
				int c = ne[a];
				wynik = max(wynik, dp[w] * (h[v] + c - a));
			}
		}
	}
}

int main() {
	ios_base::sync_with_stdio(0);
	cin >> m;
	for(int i = 1; i <= m; ++i) {
		cin >> (s + n + 1);
		while(s[n + 1]) {
			n++;
			gd[n] = i;
		}
		n++;
		s[n] = 'z' + 1;
	}
	for(int i = 1; i <= m; ++i) cin >> cost[i];
	n++;
	s[n] = 'z' + 2;
	for(int i = 1; i <= n; ++i) {
		su[i] = su[i - 1];
		if(s[i] == 'z' + 1) su[i]++;
	}

	for(int i = n; i >= 1; --i) {
		ne[i] = ne[i + 1];
		if(s[i] == 'z' + 1) ne[i] = i;
	}
	int j = 1;
	int v = 1;
	par[v] = suf[v] = 1;

	for(int i = 1; i <= n; ++i) {
		while(j <= i) {
			int u = suf[par[v]];
			if(!u) u = suf[par[par[v]]];
			pair <int, int> r = fastscan(u, j + h[u], i - j - h[u]);
			u = r.first;
			if(!r.second) {
				suf[ov] = r.first;
				ov = 0;
			}

			int w = T[u][s[j + h[u]] - 'a'];
			if(w) {
				if(s[poz[w] + r.second] == s[i]) break;
				if(r.second) {
					gid++;
					par[gid] = u;
					par[w] = gid;
					h[gid] = h[u] + r.second;
					poz[gid] = poz[w];
					poz[w] += r.second;
					len[w] -= r.second;
					len[gid] = r.second;
					suf[ov] = gid;
					ov = gid;
					T[u][s[poz[gid]] - 'a'] = gid;
					T[gid][s[poz[w]] - 'a'] = w;
					r.first = gid;
				}
			}

			u = r.first;
			gid++;
			par[gid] = u;
			poz[gid] = j + h[u];
			h[gid] = n + 1 - j;
			len[gid] = h[gid] - h[u];
			T[u][s[poz[gid]] - 'a'] = gid;
			v = gid;
			dp[gid] = cost[gd[j]];
			j++;
		}
	}

	dfs1(1);
	dfs2(1);
	cout << wynik << endl;
	return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    int cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {
        int cost;
        cin >> cost;
        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
        dir[pos] = i + 1e9;
        lf[pos] = pos;
        addSymToAutomathon(pos, ALP++, 0);
        pos++;
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (dir[automathon[ver].pos] != dir[automathon[ver].pos - automathon[ver].maxLen + 1]) {
                int lfLink = lf[automathon[ver].pos - automathon[pr].maxLen];
                int lfVer = lf[automathon[ver].pos];
                if (lfVer == lfLink) {
                    ans = max(ans, (automathon[ver].pos - lf[automathon[ver].pos]) * 1LL * automathon[ver].cost);
                }
                continue;
            }

            ans = max(ans, automathon[ver].maxLen * 1LL * automathon[ver].cost);
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP+100000, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int bad[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = 1;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[pos]) continue;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];
int bad[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            dir[pos] = i + 1e9;
            bad[pos] = 1;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;

            if (bad[automathon[ver].pos]) continue;
            automathon[pr].cost += automathon[ver].cost;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    int cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];
int bad[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {
        int cost;
        cin >> cost;
        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
        dir[pos] = i + 1e9;
        bad[pos] = 1;
        lf[pos] = pos;
        addSymToAutomathon(pos, ALP++, 0);
        pos++;
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[automathon[ver].pos]) {
                continue;
            }
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            ans = max(ans, lng * 1LL * automathon[ver].cost);
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    int cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];
int bad[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            dir[pos] = i + 1e9;
            bad[pos] = 1;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 5e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    int cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {
        int cost;
        cin >> cost;
        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
        dir[pos] = i + 1e9;
        lf[pos] = pos;
        addSymToAutomathon(pos, ALP++, 0);
        pos++;
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (dir[automathon[ver].pos] != dir[automathon[ver].pos - automathon[ver].maxLen + 1]) {
                int lfLink = lf[automathon[ver].pos - automathon[pr].maxLen];
                int lfVer = lf[automathon[ver].pos];
                if (lfVer == lfLink) {
                    ans = max(ans, (automathon[ver].pos - lf[automathon[ver].pos]) * 1LL * automathon[ver].cost);
                }
                continue;
            }

            ans = max(ans, automathon[ver].maxLen * 1LL * automathon[ver].cost);
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];
int bad[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            dir[pos] = i + 1e9;
            bad[pos] = 1;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[automathon[ver].pos]) continue;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
            if (ans == 4903142872) {
                cout << automathon[ver].pos << " " << automathon[ver].maxLen << " " << automathon[pr].maxLen << endl;
                return 0;
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[automathon[ver].pos]) continue;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
            if (ans == 4897493004) {
                cout << automathon[ver].pos << " " << automathon[ver].maxLen << " " << automathon[pr].maxLen << endl;
                return 0;
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[automathon[ver].pos]) continue;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
            if (ans == 4903142872) {

                cout << automathon[ver].pos << " " << automathon[ver].maxLen << " " << automathon[pr].maxLen << endl;
                cout << lng << " " << automathon[ver].cost << endl;
                return 0;
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[automathon[ver].pos]) continue;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
            if (ans == 4897493004) {

                cout << automathon[ver].pos << " " << automathon[ver].maxLen << " " << automathon[pr].maxLen << endl;
                cout << lng << " " << automathon[ver].cost << endl;
                return 0;
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, -1e9);
            pos++;
        }

        for (char c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 'a', cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;

            automathon[pr].cost += automathon[ver].cost;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[automathon[ver].pos]) continue;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
            if (ans == 4897493004) {

                cout << automathon[ver].pos << " " << automathon[ver].maxLen << " " << automathon[pr].maxLen << endl;
                cout << lng << " " << automathon[ver].cost << endl;
                return 0;
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[automathon[ver].pos]) continue;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
int bad[2 * MAXN];
vector <string> ss;

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = true;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, -1e9);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;

            automathon[pr].cost += automathon[ver].cost;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    long long cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int bad[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            bad[pos] = 1;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[pos]) continue;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            if (lng > automathon[pr].maxLen) {
                ans = max(ans, lng * 1LL * automathon[ver].cost);
            }
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 2e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    int cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[MAXN];
vector <string> ss;
int dir[MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {
        int cost;
        cin >> cost;
        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
        dir[pos] = i + 1e9;
        lf[pos] = pos;
        addSymToAutomathon(pos, ALP++, 0);
        pos++;
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (dir[automathon[ver].pos] != dir[automathon[ver].pos - automathon[ver].maxLen + 1]) {
                int lfLink = lf[automathon[ver].pos - automathon[pr].maxLen];
                int lfVer = lf[automathon[ver].pos];
                if (lfVer == lfLink) {
                    ans = max(ans, (automathon[ver].pos - lf[automathon[ver].pos]) * 1LL * automathon[ver].cost);
                }
                continue;
            }

            ans = max(ans, automathon[ver].maxLen * 1LL * automathon[ver].cost);
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    int cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];
int bad[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {

        int cost;
        cin >> cost;

        {
            dir[pos] = i + 1e9;
            bad[pos] = 1;
            lf[pos] = pos;
            addSymToAutomathon(pos, ALP++, 0);
            pos++;
        }

        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            int lng = automathon[ver].maxLen;
            if (automathon[ver].pos - lng + 1 <= lf[automathon[ver].pos]) {
                lng = automathon[ver].pos - lf[automathon[ver].pos];
            }
            ans = max(ans, lng * 1LL * automathon[ver].cost);
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 4e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    int cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {
        int cost;
        cin >> cost;
        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
        dir[pos] = i + 1e9;
        lf[pos] = pos;
        addSymToAutomathon(pos, ALP++, 0);
        pos++;
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (dir[automathon[ver].pos] != dir[automathon[ver].pos - automathon[ver].maxLen + 1]) {
                int lfLink = lf[automathon[ver].pos - automathon[pr].maxLen];
                int lfVer = lf[automathon[ver].pos];
                if (lfVer == lfLink) {
                    ans = max(ans, (automathon[ver].pos - lf[automathon[ver].pos]) * 1LL * automathon[ver].cost);
                }
                continue;
            }

            ans = max(ans, automathon[ver].maxLen * 1LL * automathon[ver].cost);
        }
    }
    cout << ans << endl;
    return 0;
}


#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <memory.h>
#include <map>

using namespace std;

const int MAXN = 6e5 + 1000;

int ALP = 26;
struct AState {
    map<int, int> next;
    int suffixLink;
    int maxLen;
    int cost = 0;
    int pos = 0;

    AState() {
        suffixLink = -1;
        maxLen = 0;
    }
};
AState automathon[2 * MAXN];
int lastUsed = 0;
int curVer = 0;
int lastVer = 0;

void preBuild() {
    lastVer = curVer = 0;
    automathon[curVer].suffixLink = -1;
    automathon[curVer].maxLen = 0;
}
vector <vector<int>> verH;

void addSymToAutomathon(int pos, int sym, int cost) {
    lastUsed++;
    int lastVer = lastUsed;

    automathon[lastVer].maxLen = pos + 1;
    automathon[lastVer].cost = cost;
    automathon[lastVer].pos = pos;
    int p = curVer;
    while (p != -1) {
        if (automathon[p].next.count(sym) == 0) {
            automathon[p].next[sym] = lastVer;
            p = automathon[p].suffixLink;
        } else {
            break;
        }
    }
    if (p == -1) {
        automathon[lastVer].suffixLink = 0;
    } else {

        int q = automathon[p].next[sym];
        if (automathon[p].maxLen + 1 == automathon[q].maxLen) {
            automathon[lastVer].suffixLink = q;
        } else {

            int clone = ++lastUsed;
            automathon[clone] = automathon[q];
            automathon[clone].maxLen = automathon[p].maxLen + 1;
            automathon[q].suffixLink = clone;
            automathon[clone].cost = 0;
            while (p != -1 && automathon[p].next.count(sym) && automathon[p].next[sym] == q) {
                automathon[p].next[sym] = clone;
                p = automathon[p].suffixLink;
            }
            automathon[lastVer].suffixLink = clone;
            verH[automathon[clone].maxLen].push_back(clone);
        }
    }
    curVer = lastVer;
    verH[automathon[curVer].maxLen].push_back(curVer);
}

int lf[2 * MAXN];
vector <string> ss;
int dir[2 * MAXN];
int bad[2 * MAXN];

int main(void) {
    preBuild();
    int n;
    cin >> n;
    int sumSize = 0;
    for (int i = 0; i < n; i++) {
        string si;
        cin >> si;
        ss.push_back(si);
        sumSize += si.size() + 1;
    }
    verH.resize(sumSize + 1);
    int pos = 0;
    for (int i = 0; i < n; i++) {
        int cost;
        cin >> cost;
        for (auto& c : ss[i]) {
            lf[pos] = pos == 0 ? 0 : lf[pos - 1];
            dir[pos] = i;
            addSymToAutomathon(pos, c - 26, cost);
            pos++;
        }
        dir[pos] = i + 1e9;
        bad[pos] = 1;
        lf[pos] = pos;
        addSymToAutomathon(pos, ALP++, 0);
        pos++;
    }
    int maxH = sumSize;
    long long ans = 0;
    for (int i = maxH; i >= 1; i--) {
        for (int ver : verH[i]) {
            int pr = automathon[ver].suffixLink;
            automathon[pr].cost += automathon[ver].cost;
            if (bad[automathon[ver].pos]) {
                continue;
            }
            if (dir[automathon[ver].pos] != dir[automathon[ver].pos - automathon[ver].maxLen + 1]) {
                int lfLink = automathon[ver].pos - automathon[pr].maxLen;
                int lfVer = lf[automathon[ver].pos];
                if (lfLink > lfVer) {
                    ans = max(ans, (automathon[ver].pos - lf[automathon[ver].pos]) * 1LL * automathon[ver].cost);
                }
                continue;
            }

            ans = max(ans, automathon[ver].maxLen * 1LL * automathon[ver].cost);
        }
    }
    cout << ans << endl;
    return 0;
}


//Tanuj Khattar
#include<bits/stdc++.h>
#pragma GCC optimize("O3")

using namespace std;

typedef pair<int,int>   II;
typedef vector< II >      VII;
typedef vector<int>     VI;
typedef vector< VI > 	VVI;
typedef long long int 	LL;

#define PB push_back
#define MP make_pair
#define F first
#define S second
#define SZ(a) (int)(a.size())
#define ALL(a) a.begin(),a.end()
#define SET(a,b) memset(a,b,sizeof(a))
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define si(n) scanf("%d",&n)
#define dout(n) printf("%d\n",n)
#define sll(n) scanf("%lld",&n)
#define lldout(n) printf("%lld\n",n)
#define fast_io ios_base::sync_with_stdio(false);cin.tie(NULL)

#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

//FILE *fin = freopen("in","r",stdin);
//FILE *fout = freopen("out","w",stdout);
const int INF = 1e9;
namespace SuffixTree{
  const int MAXN = 1.2e6;
  const int dollar = 257;
  int s[MAXN];
  map<int, int> to[MAXN];
  int len[MAXN]={INF}, fpos[MAXN], link[MAXN],suff[MAXN],par[MAXN];
  int node, pos, remain;
  int sz = 1, n = 0;
  int make_node(int _pos, int _len,int _par){
    fpos[sz] =  _pos;
    len [sz] = _len;
    suff[sz] = n - remain;
    par[sz] = _par;
    return sz++;
  }
  void go_edge(){
    while(pos > len[to[node][s[n - pos]]]){
      node = to[node][s[n - pos]];
      pos -= len[node];
    }
  }
  void add_letter(int c){
    s[n++] = c;int last = 0;
    for(remain++,pos++;pos > 0;remain--){
      go_edge();
      int edge = s[n - pos];
      int &v = to[node][edge];
      int t = s[fpos[v] + pos - 1];
      if(v == 0){
        v = make_node(n - pos, INF,node);
        link[last] = node;
        last = 0;
      }
      else if(t == c){
        link[last] = node;
        return;
      }
      else{
        int u = make_node(fpos[v], pos - 1,node);
        to[u][c] = make_node(n - 1, INF,u);
        to[u][t] = v;par[v] = u;
        fpos[v] += pos - 1;
        len [v] -= pos - 1;
        v = u;
        link[last] = u;
        last = u;
      }
      if(node == 0) pos--;
      else node = link[node];
    }
  }
}
const int N = int(1.2e6)+10;
int cost[N],idx[N],len,dollar[N];
LL sum[N];
char s[N];
LL ans;
void dfs(int x,int clen = 0){
  sum[x] = (SuffixTree::to[x].empty() ? cost[idx[SuffixTree::suff[x]]] : 0);
  for(auto it : SuffixTree::to[x]){
    int y = it.S,l = SuffixTree::fpos[y], r = min(len-1,l + SuffixTree::len[y] - 1);
    if(clen < 0)dfs(y,clen);
    else if(dollar[l] <= r)
      dfs(y,-INF),ans = max(ans,sum[y] * (dollar[l] - l + (dollar[l] > l ? clen : 0 )));
    else dfs(y,clen + r - l + 1);
    sum[x] += sum[y];
  }
  if(clen >= 0)
    ans = max(ans,sum[x] * clen);
}
int main()
{
  int n;si(n);
  int prv = 0;
  REP(i,n){
    scanf("%s",s);
    for(char *c = s;*c;c++)
      SuffixTree::add_letter(*c),idx[len++] = i;
    SuffixTree::add_letter(SuffixTree::dollar + i);
    idx[len++] = i;
    FOR(j,prv,len)dollar[j] = len - 1;
    prv = len;
  }
  REP(i,n)si(cost[i]);
  dfs(0);
  lldout(ans);
}


//Tanuj Khattar
#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int>   II;
typedef vector< II >      VII;
typedef vector<int>     VI;
typedef vector< VI > 	VVI;
typedef long long int 	LL;

#define PB push_back
#define MP make_pair
#define F first
#define S second
#define SZ(a) (int)(a.size())
#define ALL(a) a.begin(),a.end()
#define SET(a,b) memset(a,b,sizeof(a))
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define si(n) scanf("%d",&n)
#define dout(n) printf("%d\n",n)
#define sll(n) scanf("%lld",&n)
#define lldout(n) printf("%lld\n",n)
#define fast_io ios_base::sync_with_stdio(false);cin.tie(NULL)

#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

//FILE *fin = freopen("in","r",stdin);
//FILE *fout = freopen("out","w",stdout);
const int INF = 1e9;
namespace SuffixTree{
  const int MAXN = 2e6;
  const int dollar = 257;
  int s[MAXN];
  map<int, int> to[MAXN];
  int len[MAXN]={INF}, fpos[MAXN], link[MAXN],suff[MAXN],par[MAXN];
  int node, pos, remain;
  int sz = 1, n = 0;
  int make_node(int _pos, int _len,int _par){
    fpos[sz] =  _pos;
    len [sz] = _len;
    suff[sz] = n - remain;
    par[sz] = _par;
    return sz++;
  }
  void go_edge(){
    while(pos > len[to[node][s[n - pos]]]){
      node = to[node][s[n - pos]];
      pos -= len[node];
    }
  }
  void add_letter(int c){
    s[n++] = c;int last = 0;
    for(remain++,pos++;pos > 0;remain--){
      go_edge();
      int edge = s[n - pos];
      int &v = to[node][edge];
      int t = s[fpos[v] + pos - 1];
      if(v == 0){
        v = make_node(n - pos, INF,node);
        link[last] = node;
        last = 0;
      }
      else if(t == c){
        link[last] = node;
        return;
      }
      else{
        int u = make_node(fpos[v], pos - 1,node);
        to[u][c] = make_node(n - 1, INF,u);
        to[u][t] = v;par[v] = u;
        fpos[v] += pos - 1;
        len [v] -= pos - 1;
        v = u;
        link[last] = u;
        last = u;
      }
      if(node == 0) pos--;
      else node = link[node];
    }
  }
}
const int N = int(2e6)+10;
int cost[N],idx[N],len,dollar[N];
LL sum[N];
char s[N];
LL ans;
string S;
void dfs(int x,int clen = 0/*,string s = ""*/){
  //if(SuffixTree::to[x].empty())trace(x,SuffixTree::fpos[x],SuffixTree::suff[x],s);
  sum[x] = (SuffixTree::to[x].empty() ? cost[idx[SuffixTree::suff[x]]] : 0);
  for(auto it : SuffixTree::to[x]){
    int y = it.S,l = SuffixTree::fpos[y], r = min(len-1,l + SuffixTree::len[y] - 1);
    //trace(x,y,l,r,clen,dollar[l]);
    if(clen < 0)dfs(y,clen/*,s + S.substr(l,r-l+1)*/);
    else if(dollar[l] <= r)
      dfs(y,-INF/*,s + S.substr(l,r-l+1)*/),ans = max(ans,sum[y] * (dollar[l] - l + (dollar[l] > l ? clen : 0 )));
    else dfs(y,clen + r - l + 1/*,s + S.substr(l,r-l+1)*/);
    //trace(x,y,l,r,ans);
    sum[x] += sum[y];
  }
  //trace(x,s,ans,sum[x]);
  if(clen >= 0)
    ans = max(ans,sum[x] * clen);
}
int main()
{
  int n;si(n);
  int prv = 0;
  REP(i,n){
    scanf("%s",s);
    for(char *c = s;*c;c++)
      SuffixTree::add_letter(*c),idx[len++] = i,S += *c;
    SuffixTree::add_letter(SuffixTree::dollar + i);S += "$";
    idx[len++] = i;
    FOR(j,prv,len)dollar[j] = len - 1;
    prv = len;
  }
  //trace(S);
  REP(i,n)si(cost[i]);
  dfs(0);
  lldout(ans);
}


//Tanuj Khattar
#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int>   II;
typedef vector< II >      VII;
typedef vector<int>     VI;
typedef vector< VI > 	VVI;
typedef long long int 	LL;

#define PB push_back
#define MP make_pair
#define F first
#define S second
#define SZ(a) (int)(a.size())
#define ALL(a) a.begin(),a.end()
#define SET(a,b) memset(a,b,sizeof(a))
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define si(n) scanf("%d",&n)
#define dout(n) printf("%d\n",n)
#define sll(n) scanf("%lld",&n)
#define lldout(n) printf("%lld\n",n)
#define fast_io ios_base::sync_with_stdio(false);cin.tie(NULL)

#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

//FILE *fin = freopen("in","r",stdin);
//FILE *fout = freopen("out","w",stdout);
namespace SuffixTree{
  const int INF = 1e9;
  const int MAXN = 6e5 + 10;
  const int dollar = 257;
  int s[MAXN];
  map<int, int> to[MAXN];
  int len[MAXN]={INF}, fpos[MAXN], link[MAXN],suff[MAXN],par[MAXN];
  int node, pos, remain;
  int sz = 1, n = 0;
  int make_node(int _pos, int _len,int _par){
    fpos[sz] =  _pos;
    len [sz] = _len;
    suff[sz] = n - remain;
    par[sz] = _par;
    return sz++;
  }
  void go_edge(){
    while(pos > len[to[node][s[n - pos]]]){
      node = to[node][s[n - pos]];
      pos -= len[node];
    }
  }
  void add_letter(int c){
    s[n++] = c;int last = 0;
    for(remain++,pos++;pos > 0;remain--){
      go_edge();
      int edge = s[n - pos];
      int &v = to[node][edge];
      int t = s[fpos[v] + pos - 1];
      if(v == 0){
        v = make_node(n - pos, INF,node);
        link[last] = node;
        last = 0;
      }
      else if(t == c){
        link[last] = node;
        return;
      }
      else{
        int u = make_node(fpos[v], pos - 1,node);
        to[u][c] = make_node(n - 1, INF,u);
        to[u][t] = v;par[v] = u;
        fpos[v] += pos - 1;
        len [v] -= pos - 1;
        v = u;
        link[last] = u;
        last = u;
      }
      if(node == 0) pos--;
      else node = link[node];
    }
  }
  int finishingTouch(int prv){
    FOR(i,prv,sz)if(to[i].empty() && fpos[i] < n - 1){
      int x = make_node(n-1,INF,i);
      suff[x] = suff[i];
      to[i][s[n-1]] = x;
      len[i] = n - 1 - fpos[i];
    }
    FOR(i,prv,sz)if(to[i].empty())len[i]=1,assert(fpos[i] == n-1);
    return sz;
  }
}
const int N = int(6e5)+10;
int cost[N],idx[N],len;
LL sum[N];
char s[N];
LL ans;
string S;
void dfs(int x,int clen = 0/*,string s = ""*/){
  //trace(x,SuffixTree::to[x].empty(),clen,SuffixTree::suff[x],SuffixTree::len[x],s);
  sum[x] = (SuffixTree::to[x].empty() ? cost[idx[SuffixTree::suff[x]]] : 0);
  for(auto it : SuffixTree::to[x]){
    int y = it.S;
    int newlen = clen < 0 ? clen  : clen + SuffixTree::len[y] + -SuffixTree::INF * (idx[SuffixTree::fpos[y]] != idx[SuffixTree::fpos[y] + SuffixTree::len[y] - 1]);
    dfs(y,newlen/*,s + S.substr(SuffixTree::fpos[y],SuffixTree::len[y])*/);
    sum[x] += sum[y];
  }
  if(!SuffixTree::to[x].empty() && clen >= 0)
    ans = max(ans,sum[x] * clen);
  //trace(x,s,sum[x]);
}
int main()
{
  int n;si(n);
  int prv = 0;
  REP(i,n){
    scanf("%s",s);
    for(char *c = s;*c;c++)
      SuffixTree::add_letter(*c),idx[len++] = i,S.PB(*c);
    SuffixTree::add_letter(SuffixTree::dollar + i);S += "$";
    idx[len++] = i;
    prv = SuffixTree::finishingTouch(prv);
  }
  REP(i,n)si(cost[i]);
  dfs(0);
  lldout(ans);
}


//Tanuj Khattar
#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int>   II;
typedef vector< II >      VII;
typedef vector<int>     VI;
typedef vector< VI > 	VVI;
typedef long long int 	LL;

#define PB push_back
#define MP make_pair
#define F first
#define S second
#define SZ(a) (int)(a.size())
#define ALL(a) a.begin(),a.end()
#define SET(a,b) memset(a,b,sizeof(a))
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define si(n) scanf("%d",&n)
#define dout(n) printf("%d\n",n)
#define sll(n) scanf("%lld",&n)
#define lldout(n) printf("%lld\n",n)
#define fast_io ios_base::sync_with_stdio(false);cin.tie(NULL)

#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

//FILE *fin = freopen("in","r",stdin);
//FILE *fout = freopen("out","w",stdout);
const int INF = 1e9;
namespace SuffixTree{
  const int MAXN = 6e5 + 10;
  const int dollar = 257;
  int s[MAXN];
  map<int, int> to[MAXN];
  int len[MAXN]={INF}, fpos[MAXN], link[MAXN],suff[MAXN],par[MAXN];
  int node, pos, remain;
  int sz = 1, n = 0;
  int make_node(int _pos, int _len,int _par){
    fpos[sz] =  _pos;
    len [sz] = _len;
    suff[sz] = n - remain;
    par[sz] = _par;
    return sz++;
  }
  void go_edge(){
    while(pos > len[to[node][s[n - pos]]]){
      node = to[node][s[n - pos]];
      pos -= len[node];
    }
  }
  void add_letter(int c){
    s[n++] = c;int last = 0;
    for(remain++,pos++;pos > 0;remain--){
      go_edge();
      int edge = s[n - pos];
      int &v = to[node][edge];
      int t = s[fpos[v] + pos - 1];
      if(v == 0){
        v = make_node(n - pos, INF,node);
        link[last] = node;
        last = 0;
      }
      else if(t == c){
        link[last] = node;
        return;
      }
      else{
        int u = make_node(fpos[v], pos - 1,node);
        to[u][c] = make_node(n - 1, INF,u);
        to[u][t] = v;par[v] = u;
        fpos[v] += pos - 1;
        len [v] -= pos - 1;
        v = u;
        link[last] = u;
        last = u;
      }
      if(node == 0) pos--;
      else node = link[node];
    }
  }
}
const int N = int(6e5)+10;
int cost[N],idx[N],len,dollar[N];
LL sum[N];
char s[N];
LL ans;
void dfs(int x,int clen = 0){
  sum[x] = (SuffixTree::to[x].empty() ? cost[idx[SuffixTree::suff[x]]] : 0);
  for(auto it : SuffixTree::to[x]){
    int y = it.S,l = SuffixTree::fpos[y], r = l + SuffixTree::len[y] - 1;
    if(clen < 0)dfs(y,clen);
    else if(dollar[l] <= r)
      dfs(y,-INF),ans = max(ans,sum[y] * (clen + dollar[l] - l));
    else dfs(y,clen + r - l + 1);
    sum[x] += sum[y];
  }
  if(clen >= 0)
    ans = max(ans,sum[x] * clen);
}
int main()
{
  int n;si(n);
  int prv = 0;
  REP(i,n){
    scanf("%s",s);
    for(char *c = s;*c;c++)
      SuffixTree::add_letter(*c),idx[len++] = i;
    SuffixTree::add_letter(SuffixTree::dollar + i);
    idx[len++] = i;
    FOR(j,prv,len)dollar[j] = len - 1;
    prv = len;
  }
  REP(i,n)si(cost[i]);
  dfs(0);
  lldout(ans);
}


//Tanuj Khattar
#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int>   II;
typedef vector< II >      VII;
typedef vector<int>     VI;
typedef vector< VI > 	VVI;
typedef long long int 	LL;

#define PB push_back
#define MP make_pair
#define F first
#define S second
#define SZ(a) (int)(a.size())
#define ALL(a) a.begin(),a.end()
#define SET(a,b) memset(a,b,sizeof(a))
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define si(n) scanf("%d",&n)
#define dout(n) printf("%d\n",n)
#define sll(n) scanf("%lld",&n)
#define lldout(n) printf("%lld\n",n)
#define fast_io ios_base::sync_with_stdio(false);cin.tie(NULL)

#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

//FILE *fin = freopen("in","r",stdin);
//FILE *fout = freopen("out","w",stdout);
const int INF = 1e9;
namespace SuffixTree{
  const int MAXN = 2e6;
  const int dollar = 257;
  int s[MAXN];
  map<int, int> to[MAXN];
  int len[MAXN]={INF}, fpos[MAXN], link[MAXN],suff[MAXN],par[MAXN];
  int node, pos, remain;
  int sz = 1, n = 0;
  int make_node(int _pos, int _len,int _par){
    fpos[sz] =  _pos;
    len [sz] = _len;
    suff[sz] = n - remain;
    par[sz] = _par;
    return sz++;
  }
  void go_edge(){
    while(pos > len[to[node][s[n - pos]]]){
      node = to[node][s[n - pos]];
      pos -= len[node];
    }
  }
  void add_letter(int c){
    s[n++] = c;int last = 0;
    for(remain++,pos++;pos > 0;remain--){
      go_edge();
      int edge = s[n - pos];
      int &v = to[node][edge];
      int t = s[fpos[v] + pos - 1];
      if(v == 0){
        v = make_node(n - pos, INF,node);
        link[last] = node;
        last = 0;
      }
      else if(t == c){
        link[last] = node;
        return;
      }
      else{
        int u = make_node(fpos[v], pos - 1,node);
        to[u][c] = make_node(n - 1, INF,u);
        to[u][t] = v;par[v] = u;
        fpos[v] += pos - 1;
        len [v] -= pos - 1;
        v = u;
        link[last] = u;
        last = u;
      }
      if(node == 0) pos--;
      else node = link[node];
    }
  }
}
const int N = int(2e6)+10;
int cost[N],idx[N],len,dollar[N];
LL sum[N];
char s[N];
LL ans;
void dfs(int x,int clen = 0){
  sum[x] = (SuffixTree::to[x].empty() ? cost[idx[SuffixTree::suff[x]]] : 0);
  for(auto it : SuffixTree::to[x]){
    int y = it.S,l = SuffixTree::fpos[y], r = l + SuffixTree::len[y] - 1;
    if(clen < 0)dfs(y,clen);
    else if(dollar[l] <= r)
      dfs(y,-INF),ans = max(ans,sum[y] * (clen + dollar[l] - l));
    else dfs(y,clen + r - l + 1);
    sum[x] += sum[y];
  }
  if(clen >= 0)
    ans = max(ans,sum[x] * clen);
}
int main()
{
  int n;si(n);
  int prv = 0;
  REP(i,n){
    scanf("%s",s);
    for(char *c = s;*c;c++)
      SuffixTree::add_letter(*c),idx[len++] = i;
    SuffixTree::add_letter(SuffixTree::dollar + i);
    idx[len++] = i+1;
    FOR(j,prv,len)dollar[j] = len - 1;
    prv = len;
  }
  REP(i,n)si(cost[i+1]);
  dfs(0);
  lldout(ans);
}


//Tanuj Khattar
#include<bits/stdc++.h>

using namespace std;

typedef pair<int,int>   II;
typedef vector< II >      VII;
typedef vector<int>     VI;
typedef vector< VI > 	VVI;
typedef long long int 	LL;

#define PB push_back
#define MP make_pair
#define F first
#define S second
#define SZ(a) (int)(a.size())
#define ALL(a) a.begin(),a.end()
#define SET(a,b) memset(a,b,sizeof(a))
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)

#define si(n) scanf("%d",&n)
#define dout(n) printf("%d\n",n)
#define sll(n) scanf("%lld",&n)
#define lldout(n) printf("%lld\n",n)
#define fast_io ios_base::sync_with_stdio(false);cin.tie(NULL)

#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
  cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
  const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

//FILE *fin = freopen("in","r",stdin);
//FILE *fout = freopen("out","w",stdout);
const int INF = 1e9;
namespace SuffixTree{
  const int MAXN = 2e6;
  const int dollar = 257;
  int s[MAXN];
  map<int, int> to[MAXN];
  int len[MAXN]={INF}, fpos[MAXN], link[MAXN],suff[MAXN],par[MAXN];
  int node, pos, remain;
  int sz = 1, n = 0;
  int make_node(int _pos, int _len,int _par){
    fpos[sz] =  _pos;
    len [sz] = _len;
    suff[sz] = n - remain;
    par[sz] = _par;
    return sz++;
  }
  void go_edge(){
    while(pos > len[to[node][s[n - pos]]]){
      node = to[node][s[n - pos]];
      pos -= len[node];
    }
  }
  void add_letter(int c){
    s[n++] = c;int last = 0;
    for(remain++,pos++;pos > 0;remain--){
      go_edge();
      int edge = s[n - pos];
      int &v = to[node][edge];
      int t = s[fpos[v] + pos - 1];
      if(v == 0){
        v = make_node(n - pos, INF,node);
        link[last] = node;
        last = 0;
      }
      else if(t == c){
        link[last] = node;
        return;
      }
      else{
        int u = make_node(fpos[v], pos - 1,node);
        to[u][c] = make_node(n - 1, INF,u);
        to[u][t] = v;par[v] = u;
        fpos[v] += pos - 1;
        len [v] -= pos - 1;
        v = u;
        link[last] = u;
        last = u;
      }
      if(node == 0) pos--;
      else node = link[node];
    }
  }
}
const int N = int(6e5)+10;
int cost[N],idx[N],len,dollar[N];
LL sum[N];
char s[N];
LL ans;
void dfs(int x,int clen = 0){
  sum[x] = (SuffixTree::to[x].empty() ? cost[idx[SuffixTree::suff[x]]] : 0);
  for(auto it : SuffixTree::to[x]){
    int y = it.S,l = SuffixTree::fpos[y], r = l + SuffixTree::len[y] - 1;
    if(clen < 0)dfs(y,clen);
    else if(dollar[l] <= r)
      dfs(y,-INF),ans = max(ans,sum[y] * (clen + dollar[l] - l));
    else dfs(y,clen + r - l + 1);
    sum[x] += sum[y];
  }
  if(clen >= 0)
    ans = max(ans,sum[x] * clen);
}
int main()
{
  int n;si(n);
  int prv = 0;
  REP(i,n){
    scanf("%s",s);
    for(char *c = s;*c;c++)
      SuffixTree::add_letter(*c),idx[len++] = i;
    SuffixTree::add_letter(SuffixTree::dollar + i);
    idx[len++] = i;
    FOR(j,prv,len)dollar[j] = len - 1;
    prv = len;
  }
  REP(i,n)si(cost[i]);
  dfs(0);
  lldout(ans);
}