[CF696D]Legen...
题目
点这里看题目。
分析
首先对于模式串建立 AC 自动机,并且计算出每个状态\(p\)的贡献总和\(con(p)\)。
考虑一个朴素的 DP :
\(f(i,p)\):当前串长度为\(i\),匹配到\(p\)上的最大答案。
设在\(p\)后加入字符\(c\)会转移到\(t(p,c)\), DP 的转移如下:
\]
如何表示这种转移? 我们可以尝试一下矩阵:
\begin{cases}
con(j)&\exists c, t(i,c)=j\\
-\infty& otherwise
\end{cases}
\]
并且可以再定义一种矩阵上的新运算 ' \(\cdot\) ' :
\]
那么我们对\(T\)进行\(L\)次\(T\cdot T\),再与初始向量\(\boldsymbol v\)积起来,即是答案。也就是说,答案为:
\]
本质理解:
我们的 DP 是在做什么?你会发现,我们实际上是在 AC 自动机的有向图上面做了一个从根出发走\(l\)步的最长路。
那么\(T\)实际上是一个邻接矩阵,而 ' \(\cdot\) ' 的本质是枚举中转点计算出下一步的最长路。
其实一次“乘法”就像是做了一次 Floyd ,我们是做了基于 Floyd 的快速幂运算!
代码
#include <cstdio>
#include <cstring>
#define Tour( c ) for( int c = 0 ; c < 26 ; c ++ )
typedef long long LL;
const int MAXN = 205, MAXL = 205;
template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
}
template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
}
template<typename _T>
_T MAX( const _T a, const _T b )
{
return a > b ? a : b;
}
struct matrix
{
LL mat[MAXL][MAXL];
int n, m;
matrix() { m = n = 0, memset( mat, 0xc0, sizeof mat ); }
matrix( const int N, const int M ) { n = N, m = M, memset( mat, 0xc0, sizeof mat ); }
LL* operator [] ( const int indx ) { return mat[indx]; }
matrix operator * ( matrix b )
{
matrix ret = matrix( n, b.m );
for( int i = 1 ; i <= ret.n ; i ++ )
for( int j = 1 ; j <= ret.m ; j ++ )
for( int k = 1 ; k <= m ; k ++ )
ret[i][j] = MAX( ret[i][j], mat[i][k] + b[k][j] );
return ret;
}
void operator *= ( matrix b ) { *this = *this * b; }
};
int ch[MAXL][26], fail[MAXL], con[MAXL], q[MAXL];
int a[MAXN];
int N, cnt; LL L;
char S[MAXL];
matrix I( const int n ) { matrix ret = matrix( n, n ); for( int i = 1 ; i <= n ; i ++ ) ret[i][i] = 0; return ret; }
void insert( const int contri )
{
int p = 0, id;
for( int i = 1 ; S[i] ; i ++ )
{
id = S[i] - 'a';
if( ! ch[p][id] ) ch[p][id] = ++ cnt;
p = ch[p][id];
}
con[p] += contri;
}
void init()
{
int h = 1, t = 0, u, v;
Tour( i ) if( ch[0][i] ) q[++ t] = ch[0][i];
while( h <= t )
{
u = q[h ++];
Tour( i )
{
if( v = ch[u][i] ) fail[v] = ch[fail[u]][i], q[++ t] = v;
else ch[u][i] = ch[fail[u]][i];
}
con[u] += con[fail[u]];
}
}
matrix qkpow( matrix base, LL indx )
{
matrix ret = I( base.n );
while( indx )
{
if( indx & 1 ) ret *= base;
base *= base, indx >>= 1;
}
return ret;
}
int main()
{
read( N ), read( L );
for( int i = 1 ; i <= N ; i ++ ) read( a[i] );
for( int i = 1 ; i <= N ; i ++ ) scanf( "%s", S + 1 ), insert( a[i] );
init();
matrix A = matrix( 1, cnt + 1 ), B = matrix( cnt + 1, cnt + 1 );
for( int p = 0 ; p <= cnt ; p ++ )
Tour( c )
B[p + 1][ch[p][c] + 1] = MAX( B[p + 1][ch[p][c] + 1], ( LL ) con[ch[p][c]] );
A[1][1] = 0;
A *= qkpow( B, L );
LL ans = 0;
for( int p = 1 ; p <= cnt + 1 ; p ++ ) ans = MAX( ans, A[1][p] );
write( ans ), putchar( '\n' );
return 0;
}
[CF696D]Legen...的更多相关文章
- 【CF696D】Legen...(AC自动机)(矩阵快速幂)
题目描述 Barney was hanging out with Nora for a while and now he thinks he may have feelings for her. Ba ...
- CodeForces - 697F:Legen... (AC自动机+矩阵)
Barney was hanging out with Nora for a while and now he thinks he may have feelings for her. Barney ...
- Codeforces 696 D. Legen...
Description 每个字符串有些价值,问生成长度为 \(l\) 的字符串最多能获得多少价值,总字符数不超过 \(200\), \(l\leqslant 10^{14}\) . Sol AC自动机 ...
- Codeforces 696D Legen...(AC自动机 + 矩阵快速幂)
题目大概说给几个字符串,每个字符串都有一个开心值,一个串如果包含一次这些字符串就加上对应的开心值,问长度n的串开心值最多可以是多少. POJ2778..复习下..太弱了都快不会做了.. 这个矩阵的乘法 ...
- [Codeforces 696D] Legen...
题目大意: 给出一些匹配串,要造一个长度不超过L的字符串,每个匹配串有自己的价值,匹配串每次出现在字符串里都会贡献一次价值...要求可能得到的最大价值. 匹配串总长不超200,L<=10^14, ...
- 【Codeforces 696D】Legen...
Codeforces 696 D 题意:给\(n\)个串,每个串有一个权值\(a_i\),现在要构造一个长度为\(l\leq 10^{14}\)的串,如果其中包含了第\(i\)个串,则会得到\(a_i ...
- Codeforces Round #362(Div1) D Legen...(AC自动机+矩阵快速幂)
题目大意: 给定一些开心串,每个串有一个开心值,构造一个串,每包含一次开心串就会获得一个开心值,求最大获得多少开心值. 题解: 首先先建立AC自动机.(建立fail指针的时候,对val要进行累加) 然 ...
- codeforces泛做..
前面说点什么.. 为了完成日常积累,傻逼呵呵的我决定来一发codeforces 挑水题 泛做.. 嗯对,就是泛做.. 主要就是把codeforces Div.1的ABCD都尝试一下吧0.0.. 挖坑0 ...
- html,css命名规范 (转)
HTML+CSS命名规范总结 1.HTML部分 1.1添加必须的utf-8的字符集,并且使用HTML5的简洁 方式: <meta charset="utf-8"> 1. ...
随机推荐
- linux -- 一般使用经验(四)
一.使用grep进行条件筛选(主要为日志) 1.grep -E '条件1|条件2|条件3' 文件名 (cat -n 文件.log |grep -E '2020-01-16 15:24:48|条件 ...
- SVN:TortoiseSVN SendRpt.exe not found 完美解决
今天来上班的时候,发现公司用的svn版本和我自己的不一致,其实可以使用但是还是神经质的更新了一下.结果每次右键都会出一个异常.下图所示. 期初以为是哪里配置错误,或者版本冲突,经过网上查找办法,完美解 ...
- BZOJ1077 并查集
1077: [SCOI2008]天平 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 416 Solved: 224[Submit][Status][ ...
- Golang源码学习:调度逻辑(一)初始化
本文所使用的Golang为1.14,dlv为1.4.0. 源代码 package main import "fmt" func main() { fmt.Println(" ...
- #442-Find All Duplicates in an Array-数组中重复的数字
一.题目 给定一个整数数组 a,其中1 ≤ a[i] ≤ n (n为数组长度), 其中有些元素出现两次而其他元素出现一次. 找到所有出现两次的元素. 你可以不用到任何额外空间并在O(n)时间复杂度内解 ...
- WordPress美化百度分享默认图标
因代码中使用了Font Awesome字体图标,如果你的主题没有加载字体图标,可以到WP后台--插件--安装插件页面搜索:Font Awesome 4 Menus 安装并启用,才能显示替换后的图标. ...
- docker启动各种容器命令大全
安装步骤梳理 搜索镜像 拉取镜像 查看镜像 启动镜像 停止容器 移除容器 安装tomcat docker hub好查找tomcat镜像 docker search tomcat 从docker hu ...
- HTML元素跟随鼠标一起移动,网页中回到顶部按钮的实现
对象跟随鼠标: 1.对象css设置绝对定位position: absolute; 2.获取鼠标坐标: 3.通过鼠标坐标计算出对象坐标位置,并设置为css定位的位置: document.onmousem ...
- Java 从入门到精通-反射机制
导读 Java反射机制是开发者迈向结构化开发的重要一步,同时掌握了反射机制也就掌握了所有框架的核心实现思想. 认识反射机制 简单例子 通过以上的程序就会发现,除了对象的正向处理操作之外,还可以通过ge ...
- Java实现 LeetCode 462 最少移动次数使数组元素相等 II
462. 最少移动次数使数组元素相等 II 给定一个非空整数数组,找到使所有数组元素相等所需的最小移动数,其中每次移动可将选定的一个元素加1或减1. 您可以假设数组的长度最多为10000. 例如: 输 ...