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;
}
posted @ 2012-08-20 16:22  lxc902  阅读(217)  评论(0编辑  收藏  举报