1. 程式人生 > >ZOJ3494--BCD Code(AC自動機+數位DP)

ZOJ3494--BCD Code(AC自動機+數位DP)

題意:有T組測試資料每組一個整數n代表有n個不合格的二進位制編碼,將所有數字轉化為BCD碼 判斷區間l,r之間有多少合格的數字 (一個數只要轉化為BCD碼後中間有不合格的BCD碼該資料就不合格)
題解:先用AC自動機將不合格二進位制串處理好然後定義一個bcd[i][j]二維陣列 表示在數字中前一個數為AC自動機樹上的節點i時下一個位數為j(0~9)時合不合法 為-1表示不合法;
dp[i][j] 表示數字的第幾位 j表示前一個數為AC自動機樹上的節點i時有多少合格的數
(借鑑於大佬)程式碼:
#include <cstdio>
#include <cstring>
#include <algorithm> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <iostream> #include <vector> #include <map> #include <set> #include <stack> #include <queue> using namespace std; #define clr(a,b) memset(a,b,sizeof(a))
#define reg register #define il inline typedef long long ll; const int maxn = 2005; const int mod= 1000000009; char str[205]; class AC { public: int next[maxn][3], fail[maxn], tag[maxn]; int dig[205],bcd[maxn][10]; int root, tot; ll dp[205][maxn]; void init() { clr(dp,-
1); clr(next,-1); clr(tag,0); root =tot=0; } void insert(char *buf) { int len = strlen(buf); int now = root; for(reg int i = 0; i < len; ++i) { int id = buf[i] - '0'; now=next[now][id]!=-1?next[now][id]:(next[now][id]=++tot); } tag[now] = 1; } void build() { queue<int> q; fail[root] = root; for(reg int i = 0; i < 3; ++i) { if(next[root][i] == -1) { next[root][i] = root; } else { fail[next[root][i]] = root; q.push(next[root][i]); } } while(!q.empty()) { int now = q.front(); q.pop(); tag[now] |= tag[fail[now]]; for(reg int i = 0; i < 3; ++i) { if(next[now][i] == -1) { next[now][i] = next[fail[now]][i]; } else { fail[next[now][i]] = next[fail[now]][i]; q.push(next[now][i]); } } } } void getbcd() { for(reg int i = 0; i <=tot; ++i) { for(reg int j = 0; j < 10; ++j) { bcd[i][j] = i; if(tag[i]) bcd[i][j] = -1; int now = i; for(reg int k = 3; k >= 0; --k) {//從做到右匹配 int x = (j >> k) & 1; if(tag[next[now][x]]) { bcd[i][j] = -1; break; } else bcd[i][j] = next[now][x]; now = next[now][x]; } } } } ll dfs(int pos, int cur, int limit, int nozero) { if(pos == 0) return 1; if(dp[pos][cur] != -1 && !limit && nozero) return dp[pos][cur]; ll res = 0; for(reg int i = 0; i <= (limit ? dig[pos] : 9); ++i) { if(!nozero && i == 0) res += dfs(pos-1, cur, limit&&i==dig[pos], nozero); else if(bcd[cur][i] != -1) res += dfs(pos-1, bcd[cur][i],limit&&i==dig[pos],1); res %= mod; } if(!limit && nozero) dp[pos][cur] = res; return res; } ll solve(char *buf) { int len = strlen(buf); for(reg int i = 0; i < len; ++i) { dig[len - i] = buf[i] - '0'; } return dfs(len, root, 1, 0); } }ac; il void dec(char *buf) {//左區間後移一位 int len = strlen(buf); for(reg int i = len-1; i >= 0; --i) { if(buf[i] > '0') { buf[i] --; return ; } else buf[i] = '9'; } } int main() { int t,n; scanf("%d",&t); while(t--) { ac.init(); scanf("%d",&n); while(n--) { scanf("%s",str); ac.insert(str); } ac.build(); ac.getbcd(); scanf("%s",str); dec(str); ll ans = ac.solve(str); scanf("%s",str); printf("%lld\n",(ac.solve(str)-ans+mod)%mod); } return 0; }

相關推薦

ZOJ3494--BCD Code(AC自動機+數位DP)

題意:有T組測試資料每組一個整數n代表有n個不合格的二進位制編碼,將所有數字轉化為BCD碼 判斷區間l,r之間有多少合格的數字 (一個數只要轉化為BCD碼後中間有不合格的BCD碼該資料就不合格) 題解:先用AC自動機將不合格二進位制串處理好然後定義一個b

ZOJ-3494 BCD Code (ac自動機+數位dp)

題目連結 Problem Description Binary-coded decimal (BCD) is an encoding for decimal numbers in which each digit is represented by its own binary se

BZOJ.3530.[SDOI2014]數數(AC自動機 數位DP)

數位dp 上界 const 模式串 turn while 不可 ring href 題目鏈接 首先數位DP 用f[i][0/1]表示匹配到第i位前面i-1位是否為上界。 這樣還需要狀態轉移,對於每個狀態 枚舉每一個數,用AC自動機得到下一個狀態(這樣狀態其實就是在樹上的標號

zoj 3494 AC自動機+數位DP

這道題說實話我到現在也不能完整的把這份程式碼寫出來,大部分都是抄kuangbin部落格裡的那份程式碼,其實這份程式碼讓我讓我一個人看我差不多能看懂,但讓我寫我感覺我根本寫不了,首先我們對模式串建一個AC自動機,然後構造出來一些不可達的點,再寫成一個矩陣bcd[i][j]表示在AC自動機上

BZOJ 3530 [SDOI2014]數數 (Trie圖/AC自動機+數位DP)

題目大意:略 裸的AC自動機+數位DP吧... 定義f[i][x][0/1]表示已經匹配到了第i位,當前位置是x,0表示沒到上限,1到上限,此時數是數量 然而會出現虛擬前導零,即前幾位沒有數字的情況,實際上是在0號節點原地打轉,所以多加一維狀態,再額外討論第1位就行了 #include <

【BZOJ2553】[BeiJing2011]禁忌 AC自動機+期望DP+矩陣乘法

現在 using put 重疊 [0 return name 概念 註意 【BZOJ2553】[BeiJing2011]禁忌 Description Magic Land上的人們總是提起那個傳說:他們的祖先John在那個東方島嶼幫助Koishi與其姐姐

bzoj1444 有趣的遊戲(AC自動機+概率dp

大寫字母 叠代 字符串 字符 時間復雜度 單詞 分析 出現 ron 題意: 給定n個長度為l的模式串,現在要用前m個大寫字母生成一個隨機串,每個字符有自己的出現幾率,第一次出現的字符串獲勝,求最終每個字符串的獲勝幾率。 分析: 容易想到先把所有的字符串建成一個AC自動

【BZOJ1444】[Jsoi2009]有趣的遊戲 AC自動機+概率DP+矩陣乘法

pri 註意 script aaaaa mil size borde tput char 【BZOJ1444】[Jsoi2009]有趣的遊戲 Description Input 註意 是0<=P Output Sample

【HDOJ3341】Lost's revenge(AC自動機DP

res n) trie hdoj 字母 div 其中 func color 題意:給出一個n個模式串,一個目標串,問把目標串重新排位最多能產生多少個模式串,可以重疊且所有串只包含A C G T。 n<=10,len[i]<=10 len(s)<=40 C

HDU 3247 Resource Archiver AC自動機+BFS+dp

Resource Archiver   Great! Your new software is almost finished! The only thing left to do is archiving all your n resource files into a bi

[TJOI2013]單詞(AC自動機,樹形dp)

題目 給定個單詞,這個單詞形成一篇文章(單詞間隔斷).統計每個單詞出現次數. 資料範圍: 題解 可以看出每個單詞的貢獻是獨立的,也是對整體有影響的,便想到用樹來統計貢獻. 如果插入一個單詞(如),則每層計數的都.這樣就統計了所有字首的貢獻.如沒有計算. 考慮自動機

11468 Substring (AC自動機 + 概率dp

#include <cstdio> #include <cstring> #include <algorithm> #include <string> #include <iostream> #include <vector> #incl

隨機生成的S不包含任何一個串的概率 AC自動機+概率DP UVA 11468 Substring

題意:給出一些字元和各自對應的選擇概率,隨機選擇L次後將得到一個長度為L的隨機字串S.給出K個模版串,計算S不包含任何一個串的概率 分析:構造AC自動機之後,沒隨機生成一個字母,相當於在AC自動機中隨機走一步.所有單詞結點標記為"禁止",則本題就是求從結點0開始走L

poj:1850 Code(組合數學?數位dp!)

urn font log strlen adc i++ 分享 依次 one   題目大意:字符的字典序依次遞增才是合法的字符串,將字符串依次標號如:a-1 b-2 ... z-26 ab-27 bc-52。   為什麽題解都是組合數學的...我覺得數位dp很好寫啊(逃   

POJ 1625 Censored!(AC自動機+高精度+dp

數組實現 ons 不包含 mat queue sta uil style 矩陣 http://poj.org/problem?id=1625 題意: 給出一些單詞,求長度為m的串不包含這些單詞的個數。 思路: 這道題和HDU 2243和POJ 2778是一樣的

BZOJ1030 [JSOI2007]文本生成器 (AC自動機+DP)

init 現在 cstring ans efi sca code int 比較 題目大意:求長度為$M$的用$‘A‘-‘Z‘$組成的字符串中至少含有給出的N個模式串之一的個數。 傳送門 似乎不那麽裸的AC自動機題目都是在自動機上跑DP。。。 直接求解不好算,我們可以用

[hdu2296]Ring(AC自動機+dp)

stream style ac自動機 sizeof push 字符串 += cnblogs fail 題意:你M個單詞構成一個詞典,每個單詞有一個權值(單詞出現多次算多個權值),現在要你構造一個不超過長度N的字符串,使得該字符串權值最大。如果出現多個答案,輸出最短的,如果依

【BZOJ 2553】[BeiJing2011]禁忌 AC自動機+期望概率dp

我們 string cst def main 乘法 i++ jin 自動 我一開始想的是倒著來,發現太屎,後來想到了一種神奇的方法——我們帶著一個既有期望又有概率的矩陣,偶數(2*id)代表期望,奇數(2*id+1)代表概率,初始答案矩陣一列,1的位

手打AC的第2道數位DP:BZOJ1799: [Ahoi2009]self 同類分布

pac div cstring () ace -s 難度 搜索 bsp 先講下個人對於數位DP的看法吧。。。 挺難理解的 首先需要明白的一點:前綴和很重要 其次:必須用到記憶化搜索(本人蒟蒻,必須要用這種方法降低難度) 然後呢,需要判斷約束的條件:(1.前綴0(有時需要,有