hdu 4376
AC自动机+带上下界的数位dp。
因为题意要求要匹配的串反转也要在区间里面,所以不满足区间减法,即calc(r)-calc(l-1)这种,具体实现的时候必须要同时考虑上下界,和反转串的上下界(比较纠结)。。
View Code
#include<cstdio> #include<cstring> #define mem(a,b) memset(a,b,sizeof(a)) #include<algorithm> #include<cmath> #include<cctype> using namespace std; typedef long long ll; const int N = 20; struct Ans { ll a[3]; void clear() { mem(a,0); } Ans(){ this->clear(); } void operator += (Ans b) { for(int i=0;i<3;i++) a[i]+=b.a[i]; } }; int COUNT; const int kind = 10; struct node{ node *fail; node *next[kind]; int id; int count; int type; // 0-Alice, 1-Bob, 2-Bob's reverse node(){ fail=NULL; count=0; id=COUNT++; type=0; memset(next,NULL,sizeof(next)); } }*q[10001]; int head,tail; void insert(node *root,char *str,int tpi){ node *p=root; int i=0,index; while(str[i]){ index=str[i]-'0'; if(p->next[index]==NULL) p->next[index]=new node(); p=p->next[index]; i++; } p->count++; p->type |= 1<<tpi; } void build_ac_automation(node *root){ int i; root->fail=NULL; head=tail=0; q[head++]=root; while(head!=tail){ node *temp=q[tail++]; node *p=NULL; for(i=1;i<10;i++){ if(temp->next[i]!=NULL){ if(temp==root) temp->next[i]->fail=root; else{ p=temp->fail; while(p!=NULL){ if(p->next[i]!=NULL){ temp->next[i]->fail=p->next[i]; break; } p=p->fail; } if(p==NULL) temp->next[i]->fail=root; } q[head++]=temp->next[i]; } } } } node *maketree(ll a,ll b) { swap(a,b); COUNT=0; node *t=new node(); char sa[N*2],sb[N]; sprintf(sa,"%I64d",a); sprintf(sb,"%I64d",b); insert(t,sa,0); insert(t,sb,1); reverse(sa,sa+strlen(sa)); insert(t,sa,2); build_ac_automation(t); return t; } node *root; node *Next(node *t,int index,int&sta) { node *p=t; while(p->next[index]==NULL && p!=root) p=p->fail; p=p->next[index]; p=(p==NULL)?root:p; node *temp=p; while(temp!=root && temp->count!=-1){ if(temp->count) sta|=temp->type; temp=temp->fail; } return p; } //int tmp[N]; int d[N], n; int dd[N],dn; Ans dp[N][N*3][1<<3][3][2][3][2]; // cmp-> 0:<, 1:=, 2:> char vis[N][N*3][1<<3][3][2][3][2]; Ans dfs(int pos,int id,int sta,int cmp,int UP,int cmpd,int DOWN,node *t) { if(pos<0) { Ans ans; for(int i=0;i<2;i++) if(sta&(1<<i)) { ans.a[i]=1; // for(int i=n;i>=0;i--) putchar(tmp[i]+'0'); // puts(""); } if( (sta&(1<<1)) && (sta&(1<<2)) && cmp<=1 && cmpd>=1){ ans.a[2]=1; } return ans; } if(vis[pos][id][sta][cmp][UP][cmpd][DOWN]) return dp[pos][id][sta][cmp][UP][cmpd][DOWN]; vis[pos][id][sta][cmp][UP][cmpd][DOWN]=1; Ans&ans=dp[pos][id][sta][cmp][UP][cmpd][DOWN]; ans.clear(); int up=UP?d[pos]:9; int down=DOWN?dd[pos]:1; for(int i=(down==0?1:down);i<=up;i++) { int nxtSta=sta; node *r=Next(t,i,nxtSta); // tmp[pos]=i; int nc; if(i<d[n-pos]) nc=0; else if(i>d[n-pos]) nc=2; else nc=cmp; int ncd; if(i<dd[n-pos]) ncd=0; else if(i>dd[n-pos]) ncd=2; else ncd=cmpd; ans += dfs(pos-1,r->id,nxtSta,nc,UP&&i==up,ncd,DOWN&&i==down,r); } return ans; } Ans calc(ll x,ll y) { n=0; while(x) { d[n++]=x%10; x/=10; } mem(dd,0); dn=0; while(y) { dd[dn++]=y%10; y/=10; } Ans ans; int tn=n; while(n--) { mem(vis,0); ans+=dfs(n,root->id,0,1,n+1==tn,1,n+1>=dn,root); if(n+1==tn) for(int i=0;i<=n;i++) d[i]=9; if(n+1==dn) break; } return ans; } int main() { // freopen("a.in","r",stdin); // freopen("my.out","w",stdout); int T; scanf("%d",&T); for(int ka=1;ka<=T;ka++) { ll l,r,s,t; scanf("%I64d%I64d%I64d%I64d",&l,&r,&s,&t); root=maketree(s,t); Ans a=calc(r,l); ll ans=a.a[0] + a.a[1] - a.a[2]; printf("Case #%d: %I64d\n",ka,ans); } return 0; }