ZOJ BCD Code 记忆化搜索+数位DP+AC自动机

来源:互联网 发布:添加网络位置 ftp 编辑:程序博客网 时间:2024/06/05 03:50

题意:给定的BCD吗,当翻译十进制数时,最终形成的01串中可能有禁止出现的子串,叫我们求[a,b]中有多少个完全正确的数。

做法:对于禁止的串,直接AC自动机处理。以为a,b都是大数,所以a要先用大数减法减1。

最近不知道是不是记忆化搜索用上瘾了。。。。记录的状态是当前字符所在tire树中的位置,还有是不是数组首位,以及是不是在测层边界上的数。这个题中最首位数的处理要小心。还好只是一个RE之后就A了,本来以为可以调很久。

#include<cstdio>#include<cstring>#include<deque>#define mod 1000000009#define LL long longconst int LMT=203;const int wiz=2;const int WEI=4;using namespace std;int code[10],gra[3002][2],fail[3002],siz;bool word[3002];char num[LMT];LL dp[3002][LMT];int len;void insert(char sor[])  {      int index,current =0;      for(int i=0;sor[i];i++)      {              index=sor[i]-'0';          if(!gra[current][index])gra[current][index]=siz++;          current=gra[current][index];      }      word[current]|=1;  }  void build_ac(void)  {      int current,v;      deque<int>q;      q.clear();      for(int i=0;i<wiz;i++)      if(gra[0][i])q.push_back(gra[0][i]);      while(!q.empty())      {          current=q.front();          q.pop_front();          for(int i=0;i<wiz;i++)          if(gra[current][i])          {              v=gra[current][i];              fail[v]=gra[fail[current]][i];              word[v]|=word[fail[v]];              q.push_back(v);          }          else gra[current][i]=gra[fail[current]][i];      }  }  void init(void){ siz=1;      memset(word,0,sizeof(word));      memset(fail,0,sizeof(fail));      memset(gra,0,sizeof(gra));memset(dp,-1,sizeof(dp));memset(num,0,sizeof(num));}LL dfs(int node,int pos,bool tag,bool first){if(pos==-1){if(first){int tem=node;for(int j=WEI-1;j>=0&&!word[tem];j--)tem=gra[tem][0];return !word[tem];}else return !word[node];}if(dp[node][pos]!=-1&&!tag&&!first)return dp[node][pos];int i,j,x,end,tem;LL res=0;if(tag)end=num[pos];else end=9;for(i=first;i<=end;i++){x=code[i];tem=node;for(j=WEI-1;j>=0&&!word[tem];j--)tem=gra[tem][(x>>j)&1];if(word[tem])continue;res+=dfs(tem,pos-1,tag&&i==end,0);res%=mod;}if(first)res+=dfs(node,pos-1,tag&&i==end,1);if(!first&&!tag&&dp[node][pos]==-1)dp[node][pos]=res;return res;}void cut(){int i,j,c=1;char a[LMT];memset(a,0,sizeof(a));for(i=len-1,j=0;i>=0;i--,j++){a[j]=num[i];}memset(num,0,sizeof(num));for(i=0;i<LMT&&c;i++){a[i]=a[i]-c;if(a[i]<0){a[i]=9;c=1;}else c=0;}for(i=LMT-1;i>=0&&a[i]==0;i--);len=i+1;if(i<0)len=1;for(i=len-1,j=0;i>=0;i--,j++)num[j]=a[i];}int main(void){int T,i,n;char sec[25];LL a,b;for(i=0;i<10;i++)code[i]=i;scanf("%d",&T);while(T--){init();scanf("%d",&n);while(n--){scanf("%s",sec);insert(sec);}build_ac();scanf("%s",num);len=strlen(num);for(i=0;num[i];i++)num[i]-='0';cut();for(i=0;i<len>>1;i++)swap(num[i],num[len-i-1]);a=dfs(0,len-1,1,1);memset(num,0,sizeof(num));scanf("%s",num);len=strlen(num);for(i=0;i<len;i++)num[i]-='0';for(i=0;i<len>>1;i++)swap(num[i],num[len-i-1]);b=dfs(0,len-1,1,1);printf("%lld\n",(b-a+mod)%mod);}return 0;}


 

原创粉丝点击