【Codeforces Round 362 (Div 2)F】【AC自動機+矩陣快速冪】Legen... 長度為l字串最大能夠重複匹配的字串權值
Barney was hanging out with Nora for a while and now he thinks he may have feelings for her. Barney wants to send her a cheesy text message and wants to make her as happy as possible.
Initially, happiness level of Nora is 0. Nora loves some pickup lines like "I'm falling for you" and stuff. Totally, she knows n pickup lines, each consisting only of lowercase English letters, also some of them may be equal (in writing, but different in pronouncing or meaning though). Every time Nora sees i-th pickup line as a consecutive subsequence of Barney's text message her happiness level increases by ai. These substrings may overlap, for example, Nora will see the pickup line aa twice and the pickup line ab once in text messageaaab.
Due to texting app limits, Barney's text may have up to l characters.
Barney asked you to help him make Nora as much happy as possible, it's gonna be legen...
The first line of input contains two integers n and l (1 ≤ n ≤ 200, 1 ≤ l ≤ 1014) — the number of pickup lines and the maximum length of Barney's text.
The second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 100), meaning that Nora's happiness level increases by ai after every time seeing i-th pickup line.
The next n lines contain the pickup lines. i-th of them contains a single string si consisting of only English lowercase letter. Summary length of all pickup lines does not exceed 200.
All strings are not empty.
Print the only integer — the maximum possible value of Nora's happiness level after reading Barney's text.
3 6 3 2 1 heart earth art
6
3 6 3 2 8 heart earth art
16
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.
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre() { freopen("c://test//input.in", "r", stdin); freopen("c://test//output.out", "w", stdout); }
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }
template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }
const int N = 205, M = 0, Z = 1e9 + 7, ms63 = 0x3f3f3f3f;
const int G = 202;//矩陣大小
struct MX
{
LL v[G][G];
void O() { MS(v, 0); }
void F() { MS(v, -63); }
void E() { MS(v, -63); for (int i = 0; i < G; ++i)v[i][i] = 0; }
MX operator * (const MX &b) const
{
MX c; c.O();
for (int i = 0; i<G; i++)
{
for (int j = 0; j<G; j++)
{
c.v[i][j] = -1e18;
for (int k = 0; k<G; k++)
{
gmax(c.v[i][j], v[i][k] + b.v[k][j]);
}
}
}
return c;
}
MX operator ^ (LL p) const
{
MX y; y.E();
MX x; MC(x.v, v);
while (p)
{
if (p & 1)y = y*x;
x = x*x;
p >>= 1;
}
return y;
}
}a, b, c;
int id;
char s[N];
int fail[N];
int nxt[N][26];
int cnt[N];
void insert(char s[], int val)
{
int p = 1;
for (int i = 0; s[i]; i++)
{
int x = s[i] - 'a';
if (nxt[p][x] == 0)nxt[p][x] = ++id;
p = nxt[p][x];
}
cnt[p]+=val;
}
int getfail(int p, int x)
{
while (p)
{
if (nxt[p][x])return nxt[p][x];
p = fail[p];
}
return 1;
}
void AC_automation()
{
queue<int>q;
q.push(1);
int pap, son;
while (!q.empty())
{
pap = q.front(); q.pop();
for (int i = 0; i<26; i++)if (nxt[pap][i])
{
son = nxt[pap][i];
fail[son] = getfail(fail[pap], i);
q.push(son);
cnt[son] += cnt[fail[son]];
b.v[pap][son] = cnt[son];
}
else
{
int fl = getfail(fail[pap], i);
if(fl)b.v[pap][fl] = cnt[fl];
else b.v[pap][1] = 0;
}
}
}
void clr()
{
memset(nxt, 0, (id + 2) * 4 * 26);
memset(fail, 0, (id + 2) * 4);
memset(cnt, 0, (id + 2) * 4);
id = 1;
}
int n; LL m;
int v[N];
int main()
{
while (~scanf("%d%lld", &n, &m))
{
a.F(); a.v[1][1] = 0;
b.F();
clr();
for (int i = 1; i <= n; ++i)scanf("%d", &v[i]);
for (int i = 1; i <= n; ++i)
{
scanf("%s", s); insert(s, v[i]);
}
AC_automation();
c = a*(b ^ m);
LL ans = 0;
for (int i = 1; i <= id; ++i)gmax(ans,c.v[1][i]);
printf("%lld\n", ans);
}
return 0;
}
/*
【trick&&吐槽】
這道題使得我對AC自動機又多了一層的瞭解。
【題意】
我們有n(200)個特殊單詞,總長度不超過200。
我們要構造一個長度為l(1e14)的字串。
如果字串每包含一個給定單詞i(可重疊匹配),則我們的權值計數+a[i]
問你最大可以得到的權值
【型別】
AC自動機+矩陣快速冪
【分析】
首先,因為涉及到字串的轉移,所以我們會首先想到AC自動機。
AC自動機的節點數不會超過200,每個點可以從fail指標中傳來cnt的累積量。
由AC自動機父節點向子節點轉移的時候,我們會獲得子節點cnt的增益。
轉移除了"父節點->子節點"以外,還有"節點->fail節點的轉移",
fail節點的轉移如何實現的呢?
比如當前AC自動機節點代表的字串為abcd,然後,沒有一個為abcde的節點,
在這種情況下,如果我們擴充套件'e',就需要走到"abcde"的fail節點,
比如我們有字串節點表示"cde","abcde"的fail節點,那麼,這個轉移是有意義的,我們會獲得"cde"的權值。
參照程式碼,就是——
pap = q.front(); q.pop();
for (int i = 0; i<26; i++)if (nxt[pap][i])
{
son = nxt[pap][i];
fail[son] = getfail(fail[pap], i);
q.push(son);
cnt[son] += cnt[fail[son]];
b.v[pap][son] = cnt[son];
}
else
{
int fl = getfail(fail[pap], i);
if(fl)b.v[pap][fl] = cnt[fl];
else b.v[pap][1] = 0;
}
我們求出了節點之間的轉移情況之後,就有了轉移DP關係。
但是我們需要構建的字串太長了,於是,這個DP關係需要用快速冪來求解。
但是這個快速冪有點特殊。
因為轉移方程是這樣子的,f[nxt]=max(f[pre])+val[nxt]
是一個取max的轉移關係。
於是,轉移部分的程式碼就要是這個樣子——
for (int i = 0; i<G; i++)
{
for (int j = 0; j<G; j++)
{
c.v[i][j] = -1e18;
for (int k = 0; k<G; k++)
{
gmax(c.v[i][j], v[i][k] + b.v[k][j]);
}
}
}
在定義轉移關係初始陣列的時候,也要把其權值設定為極小值(對於一般的乘法快速冪矩陣,權值初始是設定為0的)
有一點需要特別注意的是,在我們做矩陣快速冪的冪運算時,y的初值不能全部設為最小,對角線的權值要為0。
因為這裡的y代表的是轉移n步之後額外獲得的權值增量,起點是斜對角上的所有點,故而初始權值這樣設定。
經過之前所有步驟,我們就可以順利AC啦。
【時間複雜度&&優化】
O(|字串總長|^3)
【資料】
1 3
100
s
*/
相關文章
- poj--2778DNA Sequence+AC自動機+矩陣快速冪矩陣
- Codeforces Round #213 (Div. 2)(矩陣)矩陣
- POJ 2778-DNA Sequence(AC自動機+構建鄰接矩陣+矩陣快速冪)矩陣
- Codeforces Round #362 (Div. 2) B 模擬
- Codeforces-Round#548(Div.2)-C-Edgy Trees-快速冪
- PHP二維陣列切割為字串並去除重複的值PHP陣列字串
- 矩陣快速冪矩陣
- Codeforces Round #362 (Div. 2) C 模擬二叉樹二叉樹
- 【Codeforces Round 362 (Div 2)E】【公式推導+快速冪+費馬小定理】PLEASE a[i]=(1-a[i-1])除2下n次項 n為連乘數公式
- 求字串中對稱的子字串的最大長度字串
- 生成固定長度不重複的隨機字串隨機字串
- Codeforces Round 970 (Div. 3)A~F
- 【Ac自動機+矩陣加速】poj 2778 DNA Sequence矩陣
- poj 2778 AC自動機與矩陣連乘矩陣
- hdu2243 ac自動機+矩陣連乘矩陣
- 矩陣快速冪(快忘了)矩陣
- 矩陣快速冪總結矩陣
- String字串的最大長度是多少?字串
- [複習] AC自動機
- AC 自動機——多模式串匹配模式
- 從字串中的第n位開始取l長度的子字串字串
- 【矩陣乘法】【快速冪】遞推矩陣
- 矩陣快速冪加速最短路矩陣
- HDU 2276 - Kiki & Little Kiki 2 (矩陣快速冪)矩陣
- 最長不含重複字元的子字串字元字串
- 樹形dp - Codeforces Round #322 (Div. 2) F Zublicanes and Mumocrates
- Codeforces Round 987 (Div. 2) (C~F) 題解/個人記錄
- 讓Word文件中的重複字串自動更新(轉)字串
- Codeforces Round #639 (Div. 2)
- Codeforces Round #541 (Div. 2)
- Codeforces Round #682 (Div. 2)
- Codeforces Round #678 (Div. 2)
- Codeforces Round #747 (Div. 2)
- Codeforces Round #673 (Div. 2)
- Codeforces Round #672 (Div. 2)
- Codeforces Round #448 (Div. 2) A
- Codeforces Round #217 (Div. 2)
- Codeforces Round #256 (Div. 2)