题目

描述

题目大意

给你一堆小串,每个小串都有一定的分数。

让你构造一个字符串,若子串中出现了之前的小串,就可以得到对应的分数(可以重复)

问最大分数。


思考历程

一看这题就知道是什么字符串方面的算法。

然后就很自然地想到AC自动机,多串匹配嘛!

接下来就想到建字符串的过程中,一个指针在AC自动机上跳来跳去……

先建出AC自动机,然后算出到达每个节点的贡献。

对于每个节点,枚举字母,若没有出边,就想着用failfailfail往上跳,然后将出边连向那个地方。

从此AC自动机变成了一张有向图,每个点都有262626条出边。题目就转成了在这张有向图上,走mmm步所的最大点权和。

感觉转化到这一步之后就想不出什么了,考虑过最长路一类的做法,都是没有成功。

于是我也不追求满分了,直接跑DP水分。


正解

事实上……

题目中有这么一句话:字符串的长度和不超过200200200。

知道这一切之后我疯了。

既然这样,那不就是一个裸的矩阵乘法吗?

时间就是2003lg⁡m200^3\lg m2003lgm,在6000ms中肯定是可以过的。


代码

using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
int n;
long long m;
int a[210];
char str[210];
struct Node{
int c[26],fail;
int v;
} d[210];
int cnt,root;
inline void insert(char *s,int val){
int t=root;
for (;*s;++s){
if (!d[t].c[*s-'a'])
d[t].c[*s-'a']=++cnt;
t=d[t].c[*s-'a'];
}
d[t].v+=val;
}
inline void build(){//求fail,顺便做了对空儿子的处理。显然这两步是可以放在一起的
static int q[210];
int head=0,tail=1;
d[root].fail=root;
q[1]=root;
do{
int t=q[++head];
for (int i=0;i<26;++i){
if (d[t].c[i])
q[++tail]=d[t].c[i];
if (t==root){
if (d[t].c[i])
d[d[t].c[i]].fail=root;
else
d[t].c[i]=root;
continue;
}
int nxt=d[t].fail;
while (nxt!=root && !d[nxt].c[i])
nxt=d[nxt].fail;
if (d[nxt].c[i]){
if (d[t].c[i]){
d[d[t].c[i]].fail=d[nxt].c[i];
d[d[t].c[i]].v+=d[d[nxt].c[i]].v;
}
else
d[t].c[i]=d[nxt].c[i];
}
else{
if (d[t].c[i])
d[d[t].c[i]].fail=root;
else
d[t].c[i]=root;
}
}
}
while (head!=tail);
}
struct Matrix{
long long mat[210][210];
inline void operator*=(Matrix &b){
static Matrix res;
memset(res.mat,200,sizeof res);
for (int i=1;i<=cnt;++i)
for (int j=1;j<=cnt;++j)
for (int k=1;k<=cnt;++k)
res.mat[i][j]=max(res.mat[i][j],mat[i][k]+b.mat[k][j]);
memcpy(mat,res.mat,sizeof mat);
}
} f;
inline void get_pow(Matrix &x,long long m){
static Matrix res;
memset(res.mat,200,sizeof res);
for (int i=1;i<=cnt;++i)
res.mat[i][i]=0;
for (;m;m>>=1,x*=x)
if (m&1)
res*=x;
memcpy(x.mat,res.mat,sizeof x);
}
int main(){
cnt=root=1;
scanf("%d%lld",&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
for (int i=1;i<=n;++i){
scanf("%s",str);
insert(str,a[i]);
}
build();
memset(f.mat,200,sizeof f);
for (int i=1;i<=cnt;++i)
for (int j=0;j<26;++j)
f.mat[i][d[i].c[j]]=d[d[i].c[j]].v;
get_pow(f,m);
long long ans=0;
for (int i=1;i<=cnt;++i)
ans=max(ans,f.mat[1][i]);
printf("%lld\n",ans);
return 0;
}

总结

不想说什么……

如果不是没有看到,我这题早就AC的……

最新文章

  1. curl -w,–write-out参数详解
  2. 虚拟机CentOS-mini安装完成后的网络设置
  3. java web项目启动时自动加载自定义properties文件
  4. 《GK101任意波发生器》升级固件发布(版本:1.0.2.build124)
  5. How to recover after deleting the symbolic link libc.so.6?
  6. Image控件的简单使用示例1
  7. 2014年辛星解读Javascript之DOM之冒泡和捕获
  8. 同花顺核新下单程序的&quot;界面不操作超时时间&quot;的设定
  9. MySQL 配置文件my.cnf
  10. MySQL 必知必会学习笔记(常用命令二)
  11. webstorm11.0下载地址和webstorm11.0破解程序patcher.exe下载使用方法说明 前端IDE工具的利器
  12. layer.js 注册登录切换的问题
  13. Java NIO中的通道Channel(一)通道基础
  14. ra (数论 , 莫比乌斯反演 , 整点统计)
  15. 34-ssm 最简洁的模板
  16. Newtonsoft.Json.Linq对象读取DataSet数据
  17. 【LeetCode】- Length of Last Word(最后一个单词的长度)
  18. Linux:挂载
  19. 廖雪峰Java1-2Java程序基础-2变量和数据类型
  20. js-权威指南学习笔记7

热门文章

  1. RN书签
  2. project3_NeedToLoginCalculator(需要进行登陆确认的计算器)
  3. 简单实用的makefile
  4. 【洛谷】P1009阶乘之和
  5. neo4j采坑记
  6. RDD运行原理
  7. 服务启动脚本start_boot.sh
  8. linux命令重定向&gt;、&gt;&gt;、 1&gt;、 2&gt;、 1&gt;&gt;、 2&gt;&gt;、 &lt;(转)
  9. Estimation
  10. eclipse总结source folder和Deployment Assembly部署