ZOJ 3494 BCD Code AC自动机+数位DP

来源:互联网 发布:淘宝店铺自动回复 编辑:程序博客网 时间:2024/04/30 14:49

【题目大意】

求[l,r]中,满足题意的数字的个数。如果x改为对应的BCD码的字符串,没有病毒子串,就认为合法的。如假设病毒串为“00”,数字“127”(000100100111)就是非法的,数字“7”(0111)是合法的。

【思路】

我刚开始思考,把病毒串改为对应的一个或多个10进制串,发现状态数反而改多了 =  =!。认真思考,发现根本没有必要,建立AC自动机后,类似数位DP,用dp[ i ][ j ][ k ]表示从高到低放到第i位了,j表示前i位是否都达到对应数字的最大,在AC自动机的状态为k,的方法数。之后做DP就是了。

我敲好了后,发现样例都过不到o(╯□╰)o,认真找bug后,发现数字的前导0不应该算做字符串...好吧,把第二维稍微改一下,j==0表示前i位全是0,j==2表示前i位都达到了对应数字的最大,其他用j==1表示。然后改好了,submit,WA~~又找bug,原来是求[l,r]中 l-1后也许比数字l的位数更低了,过多的前导0会使得我的程序错误,这个改好了后就能A了

【优化】

只选取有效状态:k的范围不需要是AC自动机的全部节点,只需要其中可能合法的。

预处理AC自动机的转移:因为数字0-9对应的BCD码是4位的,这个其实可以先处理下,做DP的时候直接O(1)转移。

//#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<cmath>#include<cctype>#include<string>#include<algorithm>#include<iostream>#include<ctime>#include<map>#include<set>using namespace std;#define MP(x,y) make_pair((x),(y))#define PB(x) push_back(x)//typedef __int64 LL;//typedef unsigned __int64 ULL;/* ****************** */const int INF = 100011122;const double INFF = 1e100;const double eps = 1e-8;const int mod = 1000000009;const int NN = 210;const int MM = 5000010;/* ****************** */const int k_size = 2;const int SUM_LEN = 2005;struct Tire_tree{    int fail;    bool ok;    int next[k_size];    void init()    {        memset(next, -1, sizeof(next));        fail = -1;        ok = true;    }}tire[SUM_LEN];int tire_q[SUM_LEN];char ss[SUM_LEN];int re[SUM_LEN];//有效状态int dui[SUM_LEN];bool vis[SUM_LEN];int a[205];int dp[2][3][2005];int bian4[SUM_LEN][10],ok4[SUM_LEN][10];void tire_insert(char* ss,int root,Tire_tree* tire,int& tire_cnt){    int i, x, p = root;    for(i = 0; ss[i]; i++)    {        x = ss[i]-'0';        if(tire[p].next[x]==-1)        {            tire[p].next[x] = ++tire_cnt;            tire[tire_cnt].init();        }        p = tire[p].next[x];    }    tire[p].ok = false;}int init_fail(int root,Tire_tree* tire,int& tire_cnt){    int i, p, fa, head, tail;    int tol, zt, j, k, nn[4] = {8, 4, 2, 1};    bool fg;    p = root;    head = 1;    tail = 0;    tire[root].fail = root;    for(i = 0; i < k_size; i++)    {        if(tire[p].next[i]!=-1)        {            tire_q[++tail]  = tire[p].next[i];            tire[ tire_q[tail] ].fail = root;        }        else            tire[p].next[i] = root;    }    while(head<=tail)    {        p = tire_q[head++];        fa = tire[p].fail;        if(!tire[fa].ok)            tire[p].ok = false;        for(i = 0; i < k_size; i++)        {            if(tire[p].next[i]!=-1)            {                tire_q[ ++tail ] = tire[p].next[i];                tire[ tire_q[tail] ].fail = tire[fa].next[i];            }            else                tire[p].next[i] = tire[fa].next[i];        }    }    for(i = 0; i <= tire_cnt; i++)        vis[i] = false;    vis[root] = true;    tire_q[head = tail = 0] = root;    while(head <= tail)    {        fa = tire_q[head++];        for(i = 0; i < k_size; i++)        {            p = tire[fa].next[i];            if(tire[p].ok && !vis[p])            {                tire_q[++tail] = p;                vis[p] = true;            }        }    }    tol = 0;    for(i = 0; i <= tire_cnt; i++)    {        if(vis[i])        {            re[++tol] = i;            dui[i] = tol;        }    }    for(i = 1; i <= tol; i++)    {        for(k = 0; k < 10; k++)        {            fg = true;            zt = re[i];            for(j = 0; j < 4; j++)            {                if(k&nn[j])                    zt = tire[zt].next[1];                else                    zt = tire[zt].next[0];                fg = fg&tire[zt].ok;            }            zt = dui[zt];            bian4[i][k] = zt;            ok4[i][k] = fg;        }    }    return tol;}void INC(int& a,int b){    a += b;    if(a >= mod) a -= mod;}int solve(char* ss,int tol,int del){    int i, t, j, k, zt, cnt = 0;    bool fg;    int j1, j2, en;    for(i = 0; ss[i]; i++, cnt++)    {        a[i+1] = ss[i]-'0';    }    a[cnt] -= del;    for(i = cnt; i >= 1 ;i--)    {        if(a[i] < 0)        {            a[i] += 10;            a[i-1] -= 1;        }        else            break;    }    for(i = 1; i<cnt; i++)    {        if(a[i]!=0)            break;    }    for(j = 1; i<=cnt; i++,j++)    {        a[j] = a[i];    }    cnt = j-1;//    cout<<"cnt=="<<cnt<<endl;//    cout<<"shu==";//    for(i = 1; i <= cnt; i++)//    {//        cout<<a[i]<<" ";//    }//    cout<<endl;    memset(dp, 0, sizeof(dp));    dp[0][2][1] = 1;    t = 0;    for(i = 0; i < cnt; i++)    {        t = 1-t;        for(j = 1; j <= tol; j++)            dp[t][0][j] = dp[t][1][j] = dp[t][2][j] = 0;        for(j = 1; j <= tol; j++)        {            for(j1 = 0; j1 < 3; j1++)            {                if(dp[1-t][j1][j]==0)continue;                if(j1==2)en = a[i+1];                else en = 9;                for(k = 0; k <= en; k++)                {                    if(k==0 && (j1==0 || i==0))                    {                        fg = true;                        zt = j;                    }                    else                    {                        zt = bian4[j][k];                        fg = ok4[j][k];                    }                    if(fg)                    {                        if(j1==2 && k==en)                            j2 = 2;                        else if(k==0 && (i==0 || j1==0))                            j2 = 0;                        else                            j2 = 1;                        INC(dp[t][j2][zt],dp[1-t][j1][j]);                    }                }            }        }    }    int ans = 0;    for(j = 1; j <= tol; j++)    {        INC(ans, dp[t][0][j]);        INC(ans, dp[t][1][j]);        INC(ans, dp[t][2][j]);    }    return ans;}int main(){    int cas;    int i, n;    int root, tire_cnt;    int tol, ans;    scanf("%d",&cas);    while(cas--)    {        root = tire_cnt = 0;        tire[root].init();        scanf("%d",&n);        for(i = 0; i < n; i++)        {            scanf("%s",ss);            tire_insert(ss, root, tire, tire_cnt);        }//        for(i = 0; i <= tire_cnt; i++)//        {//            cout<<"check== "<<tire[i].next[0]<<" "<<tire[i].next[1]<<endl;//        }        tol = init_fail(root, tire, tire_cnt);//        cout<<"tol=="<<tol<<endl;//        for(i = 0; i <= tire_cnt; i++)//        {//            cout<<"check== "<<tire[i].next[0]<<" "<<tire[i].next[1]<<endl;//        }//        for(i = 1; i <= tol; i++)//        {//            cout<<"re=="<<re[i]<<endl;//        }//        cout<<dui[0]<<" "<<dui[1]<<endl;        scanf("%s",ss);        ans = -solve(ss, tol, 1);       // cout<<"ans1=="<<-ans<<endl;        scanf("%s",ss);      //  cout<<"ans2=="<<solve(ss,tol,0)<<endl;        ans += solve(ss, tol, 0);        if(ans < 0)ans += mod;      //  cout<<"ans==";        printf("%d\n",ans);    }    return 0;}


0 0
原创粉丝点击