CF696D AC自动机+矩阵快速幂

点击打开链接

题意: 

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());  
    }  
  
}  






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值