首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

HDU 2825 Wireless Password:AC 自動機 + DP 狀態壓縮

     編輯:C++ 入門

問題描述

密碼長度 n (≤25),小寫字母組成。給定 m (≤10) 個魔法單詞,密碼需包含至少 k 個魔法單詞(可重疊)。求合法密碼數模 20090717。

核心思路:AC 自動機 + DP

  • 構建所有魔法單詞的 AC 自動機,每個節點記錄以該節點結尾的單詞集合(bitmask)。
  • DP 狀態:dp[pos][node][mask] 表示構建到第 pos 位,自動機處於 node,已匹配單詞集合為 mask 的方案數。
  • 轉移:枚舉下一字符 'a'~'z',沿自動機轉移,更新 mask(或上輸出鏈上的單詞)。
  • 答案:sum(dp[n][*][mask]) 其中 mask 中 1 的個數 ≥ k。

關鍵數據結構


const int MAXN = 150; // 節點上限:10個單詞 × 長度10
const int SIGMA = 26;
int ch[MAXN][SIGMA]; // 轉移
int val[MAXN];       // 輸出 bitmask
int fail[MAXN];      // 失敗指針
int last[MAXN];      // 輸出鏈
int sz = 1;          // 節點計數

構建 AC 自動機

  1. 插入單詞:建立 Trie,葉節點 val 設置對應 bit (1<<i)。
  2. 構建 fail 指針:BFS,fail[u] = ch[fail[parent]][c],合併輸出 val[u] |= val[fail[u]],設置 last[u] 指向最近有輸出的祖先。

DP 遞推


dp[0][0][0] = 1;
for (int i = 0; i < n; ++i)
  for (int u = 0; u < sz; ++u)
    for (int mask = 0; mask < (1<

狀態壓縮優化

  • m ≤ 10,mask 最大 1024,狀態總數 25 × 150 × 1024 ≈ 380 萬,時間空間均可接受。
  • 預計算 popcount[mask] 加速最終統計。

完整代碼框架


#include <bits/stdc++.h>
using namespace std;
const int MOD = 20090717;
const int MAXN = 150, SIGMA = 26, MAXM = 11, MAXL = 30;
int ch[MAXN][SIGMA], val[MAXN], fail[MAXN], last[MAXN], sz;
int dp[MAXL][MAXN][1<>1] + (i&1);
    int n, m, k;
    while (cin >> n >> m >> k, n||m||k) {
        sz = 1; memset(ch[0], 0, sizeof ch[0]); val[0]=0;
        for (int i = 0; i < m; ++i) {
            string s; cin >> s; insert(s, i);
        }
        build();
        cout << solve(n, m, k) << '\n';
    }
}

複雜度分析

  • 時間:O(n × sz × 2^m × Σ) ≈ 25 × 150 × 1024 × 26 ≈ 10⁸ 操作,常數較小,C++ 可過。
  • 空間:dp 數組 25 × 150 × 1024 × 4B ≈ 15 MB,符合限制。

總結

本題是「多模式串匹配計數」的經典模型:AC 自動機處理重疊匹配,DP 狀態壓縮記錄已匹配集合。關鍵在於正確構建 fail 指針與輸出鏈合併,以及 DP 狀態設計無遺漏無重複。模板化後可解決所有「字符串包含至少 k 個給定模式」類問題。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved