中等的字符串 [Ac自动机, 矩阵乘法(max)]

mac2024-08-03  61

中 等 的 字 符 串 中等的字符串


正 解 部 分 \color{red}{正解部分}

建出 A c Ac Ac 自动机, 在自动机上 d p dp dp,

F [ i , j ] F[i, j] F[i,j] 表示 i i i 节点走 j j j 步所能得到的 最大值, 则 F [ i , j ] = max ⁡ ( F [ t o , j − 1 ] + w t o ) F[i, j] = \max(F[to, j-1] + w_{to}) F[i,j]=max(F[to,j1]+wto), 时间复杂度 O ( N M 2 ) O(NM^2) O(NM2) .

继续优化, 建立两个矩阵如下

[ F 1 , 0 F 2 , 0 , F 3 , 0   . . .   F t o t , 0 ] \begin{bmatrix} F_{1,0} F_{2,0}, F_{3,0}\ ...\ F_{tot,0}\end{bmatrix} [F1,0F2,0,F3,0 ... Ftot,0]

[ − i n f − i n f − i n f   . . .   − i n f w a         w a       w a     . . .       w a w b         w b       w b     . . .       w b . . . − i n f − i n f − i n f   . . .   − i n f ] \begin{bmatrix} -inf -inf-inf\ ...\ -inf\\ w_{a}\ \ \ \ \ \ \ w_{a}\ \ \ \ \ w_{a}\ \ \ ...\ \ \ \ \ w_{a} \\w_{b}\ \ \ \ \ \ \ w_{b}\ \ \ \ \ w_{b}\ \ \ ...\ \ \ \ \ w_{b} \\ . \\ . \\ . \\ -inf -inf-inf\ ...\ -inf \end{bmatrix} infinfinf ... infwa       wa     wa   ...     wawb       wb     wb   ...     wb...infinfinf ... inf

将两个矩阵相乘, 将加法替换为 max ⁡ \max max 操作, 乘法替换为加法, 可以得到 [ F 1 , 1 = max ⁡ ( F 1 , 0 − i n f , F 1 , 0 + w 1 , . . . , F 1 , 0 + w t o t ) , . . . F t o t , 1 ] [F_{1,1} = \max(F_{1,0}-inf, F_{1,0}+w_1,...,F_{1,0} + w_{tot}), ...F_{tot,1}] [F1,1=max(F1,0inf,F1,0+w1,...,F1,0+wtot),...Ftot,1] .

于是矩阵 2 2 2 N N N 次幂乘上 矩阵 1 1 1 即可得到答案矩阵 .


实 现 部 分 \color{red}{实现部分}

注意 单位矩阵 为 [ 0   − i n f   . . .   − i n f − i n f   0   . . .   − i n f . . . . . . . . . . . . . . . − i n f   − i n f   . . .   0 ] \begin{bmatrix} 0 \ -inf\ ... \ -inf \\ -inf\ 0 \ ...\ -inf \\ ............... \\ -inf\ -inf\ ...\ 0\end{bmatrix} 0 inf ... infinf 0 ... inf...............inf inf ... 0 #include<bits/stdc++.h> #define reg register #define fi first #define se second #define pb push_back typedef long long ll; typedef std::pair<ll, int> pr; const int maxn = 100004; const ll inf = 0x3f3f3f3f3f3f3f3f; int M; int A[maxn]; int dep[maxn]; int node_cnt; ll N; ll F[20004][105]; bool vis[maxn]; char Smp[205]; std::vector <int> Mp[27]; struct Node{ int nxt, ch[30], p; } Trie_t[maxn]; void Add(char *s, int x){ int len = strlen(s), cur = 0; for(reg int i = 0; i < len; i ++){ int t = s[i]; if(!Trie_t[cur].ch[t-'a']){ Trie_t[cur].ch[t-'a'] = ++ node_cnt; Mp[t-'a'].pb(node_cnt); dep[node_cnt] = dep[cur] + 1; } cur = Trie_t[cur].ch[t-'a']; } Trie_t[cur].p += x; } void Build_Ac(){ std::queue <int> Q; for(reg int i = 0; i < 26; i ++) if(Trie_t[0].ch[i]) Q.push(Trie_t[0].ch[i]); while(!Q.empty()){ int ft = Q.front(); Q.pop(); Trie_t[ft].p += Trie_t[Trie_t[ft].nxt].p; for(reg int i = 0; i < 26; i ++){ int &to = Trie_t[ft].ch[i]; if(to) Trie_t[to].nxt = Trie_t[Trie_t[ft].nxt].ch[i], Q.push(to); else to = Trie_t[Trie_t[ft].nxt].ch[i]; } } } struct Matrix{ ll v[205][205]; friend Matrix operator * (const Matrix &a, const Matrix &b){ Matrix s; for(reg int i = 1; i <= node_cnt+1; i ++) for(reg int j = 1; j <= node_cnt+1; j ++) s.v[i][j] = -inf; for(reg int i = 1; i <= node_cnt+1; i ++) for(reg int j = 1; j <= node_cnt+1; j ++) for(reg int k = 1; k <= node_cnt + 1; k ++) s.v[i][j] = std::max(s.v[i][j], a.v[i][k]+b.v[k][j]); return s; } } P, I; Matrix Ksm(Matrix a, ll b){ Matrix s; for(reg int i = 1; i <= node_cnt+1; i ++) for(reg int j = 1; j <= node_cnt+1; j ++) s.v[i][j] = (i==j)?0:-inf; while(b){ if(b & 1) s = s * a; a = a * a; b >>= 1; } return s; } void Fuck(){ for(reg int i = 1; i <= node_cnt+1; i ++) for(reg int j = 1; j <= node_cnt+1; j ++) P.v[i][j] = -inf; for(reg int i = 1; i <= node_cnt+1; i ++) P.v[1][i] = 0; I.v[1][1] = -inf; for(reg int i = 1; i <= node_cnt+1; i ++) for(reg int j = 1; j <= node_cnt+1; j ++) I.v[i][j] = -inf; for(reg int u = 0; u <= node_cnt; u ++) for(reg int i = 0; i < 26; i ++) I.v[Trie_t[u].ch[i]+1][u+1] = Trie_t[Trie_t[u].ch[i]].p; I = Ksm(I, N); P = P * I; printf("%lld\n", P.v[1][1]); } int main(){ scanf("%lld%d", &N, &M); for(reg int i = 1; i <= M; i ++) scanf("%d", &A[i]); for(reg int i = 1; i <= M; i ++){ scanf("%s", Smp); Add(Smp, A[i]); } Build_Ac(); Fuck(); return 0; }
最新回复(0)