1. 程式人生 > >UVa Live 3942 Remember the Word - Hash - 動態規劃

UVa Live 3942 Remember the Word - Hash - 動態規劃

ble body ng- 哪些 AR AC dex pro 平板電視

題目傳送門

  高速路出口I

  高速路出口II

題目大意

  給定若幹種短串,和文本串$S$,問有多少種方式可以將短串拼成長串。

  顯然,你需要一個動態規劃。

  用$f[i]$表示拼出串$S$前$i$個字符的方案數。

  轉移是顯然的。枚舉上一個拼接的串的長度,然後判斷它是否存在,如果存在就把$f[i]$加上$f[i - l]$。

  這個判斷存在可以用Hash。當然可以對每個短串的反串建立Trie樹,然後在Trie樹上查一查$i$往前會走到長度為哪些的終止狀態。

  由於我懶,不想寫Trie樹,直接用平板電視的hash表,然後慢得起飛。

Code

 1
/** 2 * UVa Live 3 * Problem#3942 4 * Accepted 5 * Time: 603ms 6 */ 7 #include <ext/pb_ds/assoc_container.hpp> 8 #include <ext/pb_ds/hash_policy.hpp> 9 #include <iostream> 10 #include <cstring> 11 #include <cstdlib> 12 #include <cstdio> 13 using namespace
std; 14 using namespace __gnu_pbds; 15 typedef bool boolean; 16 17 #define ui unsigned int 18 19 const int N = 3e5 + 5, M = 20071027, L = 101; 20 const ui base = 200379; 21 22 int n; 23 char S[N], buf[L]; 24 ui ha[N], ps[N]; 25 cc_hash_table<int, boolean> mp[L]; 26 27 inline void prepare() {
28 ps[0] = 1; 29 for (int i = 1; i < N; i++) 30 ps[i] = ps[i - 1] * base; 31 } 32 33 inline boolean init() { 34 if (scanf("%s", S + 1) == EOF) return false; 35 scanf("%d", &n); 36 for (int i = 1; i < L; i++) 37 mp[i].clear(); 38 int l; 39 ui s; 40 for (int i = 1; i <= n; i++) { 41 scanf("%s", buf); 42 for (l = 0, s = 0; buf[l]; l++) 43 s = (s * base) + buf[l]; 44 mp[l][s] = true; 45 } 46 return true; 47 } 48 49 int f[N]; 50 inline void solve() { 51 f[0] = 1, ha[0] = 0; 52 n = strlen(S + 1); 53 for (int i = 1; i <= n; i++) 54 ha[i] = ha[i - 1] * base + S[i]; 55 for (int i = 1; i <= n; i++) { 56 f[i] = 0; 57 for (int j = 1; j < L && j <= i; j++) { 58 ui s = ha[i] - ha[i - j] * ps[j]; 59 if (mp[j].find(s) != mp[j].end()) 60 f[i] = (f[i] + f[i - j]) % M; 61 } 62 } 63 printf("%d\n", f[n]); 64 } 65 66 int kase = 0; 67 int main() { 68 prepare(); 69 while(init()) { 70 printf("Case %d: ", ++kase); 71 solve(); 72 } 73 return 0; 74 }

UVa Live 3942 Remember the Word - Hash - 動態規劃