ZOJ3494--BCD Code(AC自動機+數位DP)
題解:先用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(有時需要,有