题意:
n个串s[i],权重value[i] ;
求构建长度为K(10^14)的字符串,使得总权重最大, 总权重:包含n串的权重之和。
hint:n个总的字符串长度之和<=200
Examples
input
3 6 3 2 1 heart earth art
output
6
input
3 6 3 2 8 heart earth art
output
16
Note
An optimal answer for the first sample case is hearth containing each pickup line exactly once.
An optimal answer for the second sample case is artart.
做法:
1、建立自动机,在树上转移状态,矩阵(u,v) 表示自动机节点u->节点v 的转移状态。
2、求一次dojob即一次Floyd运算,(可看着乘法运算)
3、满足结合律
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Queue;
import java.util.StringTokenizer;
public class Main {
public static void main(String[] args) {
new Task().solve() ;
}
}
class Task{
InputReader in = new InputReader(System.in) ;
PrintWriter out = new PrintWriter(System.out) ;
AhoCorasick ac = new AhoCorasick() ;
void solve(){
int n = in.nextInt() ;
long m = in.nextLong() ;
long[] va = new long[n] ;
for(int i = 0 ; i < n ; i++){
va[i] = in.nextLong() ;
}
ac.clear();
for(int i = 0 ; i < n ; i++){
ac.add(in.next() , va[i]) ;
}
ac.build() ;
int limit = ac.total ;
Mat A = new Mat(limit) ;
for(int i = 0 ; i < limit ; i++){
for(int j = 0 ; j < ac.ALPHA_SIZE ; j++){
int u = i ;
int v = ac.next[i][j] ;
A.v[u][v] = ac.value[v] ;
}
}
A = A.pow(m) ;
long sum = 0 ;
for(int i = 1 ; i < limit ; i++) sum = Math.max(sum , A.v[0][i]) ;
out.println(sum) ;
out.flush() ;
}
}
class AhoCorasick{
final int NODE_SIZE = 208 ;
final int ALPHA_SIZE = 26 ;
final int NULL = 0 ;
int[][] next = new int[NODE_SIZE][ALPHA_SIZE] ;
int[] fail = new int[NODE_SIZE] ;
long[] value = new long[NODE_SIZE] ;
int root ;
int total ;
void clear(){
total = 0 ;
root = newNode() ;
}
int newNode(){
value[total] = 0 ;
Arrays.fill(next[total] , NULL) ;
return total++ ;
}
void add(String word , long v){
int now = root ;
for(char c : word.toCharArray()){
int son = c - 'a' ;
if(next[now][son] == NULL) next[now][son] = newNode() ;
now = next[now][son] ;
}
value[now] += v ;
}
void build(){
Queue<Integer> q = new LinkedList<Integer>() ;
for(int son = 0 ; son < ALPHA_SIZE ; son++){
if(next[root][son] == NULL) next[root][son] = root ;
else{
fail[next[root][son]] = root;
q.add(next[root][son]) ;
}
}
while(! q.isEmpty()){
int u = q.poll() ;
for(int son = 0 ; son < ALPHA_SIZE ; son++){
if(next[u][son] == NULL) next[u][son] = next[fail[u]][son] ;
else{
fail[next[u][son]] = next[fail[u]][son] ;
value[next[u][son]] += value[next[fail[u]][son]] ;
q.add(next[u][son]) ;
}
}
}
}
}
class Mat{
int m ;
long[][] v ;
@Override
public String toString() {
return "Mat [m=" + m + ", v=" + Arrays.deepToString(v) + "]";
}
Mat(int m){
this.m = m ;
v = new long[m][m] ;
for(int i = 0 ; i < m ; i++) Arrays.fill(v[i] , -1) ;
}
Mat(Mat o) {
m = o.m ;
v = new long[m][m] ;
for(int i = 0 ; i < m ; i++)
for(int j = 0 ; j < m ; j++ ) v[i][j] = o.v[i][j] ;
}
Mat doJob(Mat o){
Mat res = new Mat(m) ;
for(int i = 0 ; i < m ; i++){
for(int j = 0 ; j < m ; j++){
for(int k = 0 ; k < m ; k++){
if(v[i][k] == -1 || o.v[k][j] == -1) continue ;
res.v[i][j] = Math.max(res.v[i][j] , v[i][k] + o.v[k][j]) ;
}
}
}
return res ;
}
Mat pow(long k){
Mat A = new Mat(this) ;
if(k == 1) return A ;
Mat res = new Mat(this) ;
k-- ;
for( ; k > 0 ; k>>=1){
if((k&1) == 1) res = res.doJob(A) ;
A = A.doJob(A) ;
}
return res ;
}
}
class InputReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = new StringTokenizer("");
}
private void eat(String s) {
tokenizer = new StringTokenizer(s);
}
public String nextLine() {
try {
return reader.readLine();
} catch (Exception e) {
return null;
}
}
public boolean hasNext() {
while (!tokenizer.hasMoreTokens()) {
String s = nextLine();
if (s == null)
return false;
eat(s);
}
return true;
}
public String next() {
hasNext();
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
}