題目鏈結
題目大意:給定一些被禁止的bcd碼。問指定範圍內不含有任何這些禁止的bcd碼的數的個數。
解題思路:
ac自動機部分:
首先insert這些被禁止的bcd碼。
然後打一下自動機前後狀態的轉移的表,用bcd[i][j]表示自動機狀態i時,下乙個數字是j的自動機的下乙個狀態。
一開始我考慮最先dfs的位在自動機的位置,後來發現sb了。ac自動機有乙個root狀態,也就是自動機位置為0的狀態,使用這個0就行了。
即f函式中dfs(len,0,true,true),每次由root狀態出發,無須再考慮其它的。
數字dp部分:
本題的範圍是高精度範圍,所以需要特有的高精度寫法。
麻煩的在於f(l-1),要為高精度手艹乙個-1,有種偷懶的寫法,不過會導致出現前導0。
所以在傳統的dfs中需要增加乙個前導0的判斷。
方法是:追加乙個bool z,
在原有的0~9基礎上,單獨考慮0,
if(z) 則單獨dfs前導0
否則dfs正常的0,1~9照常dfs。當然還需要判斷當前狀態s的下乙個狀態bcd[s][i]是否符合要求。
然後最後就是注意一下負數mod。
#include "cstdio
"#include
"cstring
"#include
"queue
"#include
"iostream
"using
namespace
std;
#define maxp 25*105
#define mod 1000000009
struct
trie
pool[maxp],*root,*sz;
int bcd[maxp][10],digit[205
],ccnt;
long
long dp[205
][maxp];
trie *newnode()
void
init()
void insert(string
str)
pos->cnt++;
}void
getfail()
else root->next[c]=root;
}while(!q.empty())
else x->next[c]=x->fail->next[c];}}
}int judge(int status,int
num)
return pos-pool;
}void
getbcd()
int dfs(int len,int s,bool fp,bool
z)
else
for(int i=1;i<=fpmax;i++)
if(!fp&&!z) dp[len][s]=ret;
return
ret;
}int f(string
str)
intmain()
getfail();
ccnt=sz-pool;
getbcd();
cin>>tt;
for(int i=tt.size()-1;i>=0;i--)
else
}long
long ans=0
; ans-=f(tt);
ans%=mod;
cin>>tt;
ans+=f(tt);
ans=(ans%mod+mod)%mod;
printf(
"%lld\n
",ans);
}}
2842327
neopenx
zoj 3494
accepted
4656 kb
210 ms
c++ (g++ 4.4.5)
2976 b
2014-10-13 17:06:35
ZOJ 3494 AC自動機 數字DP
有一種bcd編碼方案,求a到b範圍內的數字的bcd編碼有多少個不包含不能包含的字串。數字範圍這麼大,很明顯就能看出來是數字dp。基於ac自動機的數字dp使得數字dp容易了不少,因為ac自動機自帶狀態轉移。在數字dp選取每一位的時候,基於ac自動機狀態轉移一下,如果轉移到不能轉移的狀態,就直接返回 1...
zoj3494 ac自動機 數字dp
題解 把給的串建ac自動機,然後得到的bcd i j bcd i j 表示在ac自動機上的狀態i,後面加入j會轉移的狀態,1表示不能加 然後數字dp,dp i j 表示取到第i位狀態為j後面的數字隨便取的方案數,這裡是記憶化。include include include include inclu...
zoj3430 AC自動機模擬
jibancanyang author jibancanyang created time 五 5 6 16 14 59 2016 file name jy.cpp problem analyse 此題難就難在編碼,還有題意問的是病毒有多少種不是多少個,注意char已經不能表示解碼之後的字元,要用 ...