[51nod 1587]半现串

来源:互联网 发布:arp scan python 编辑:程序博客网 时间:2024/04/30 04:41

题目大意

有两个串S,T。T的长度是d。我们说T在S中半现的条件是当T的某一个长度为 ⌊d/2⌋ 的子串是S的一个子串。(子串是在原串中连续出现的一段字符串)。
现在给定一个原串s,另外给出x,y,他们都只包含数字字符,问区间[x,y]中在s中半现的数字有多少个。

经典套路

先转化为补集问题。
将S所有长度为d/2的串弄个AC自动机,然后做数位DP,f[i,j]表示做到第i位匹配到状态j。
匹配成功状态不要转移。

#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxtot=30000+10,mo=1000000007;char s[1200],h[1200];int g[maxtot][10],next[maxtot][10],fail[maxtot],a[1000],b[1000],c[1000],d[1000],dl[maxtot];bool bz[maxtot],czy;int f[60][maxtot];int i,j,k,l,r,t,n,m,tot,root,head,tail,ans,num;char ch;char get(){    char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    return ch;}void insert(int &x,int y){    if (!x) x=++tot;    if (y>m/2){        bz[x]=1;        return;    }    insert(g[x][h[y]-'0'],y+1);}void prepare(){    dl[tail=1]=root;    fail[root]=root;    fo(i,0,9) next[root][i]=root;    while (head<tail){        k=dl[++head];        bz[k]|=bz[fail[k]];        fo(i,0,9)            if (g[k][i]) next[k][i]=g[k][i];else next[k][i]=next[fail[k]][i];        fo(i,0,9)            if (g[k][i]){                if (k==root){                    dl[++tail]=g[k][i];                    fail[g[k][i]]=root;                    continue;                }                j=fail[k];                while (j!=root&&!g[j][i]) j=fail[j];                if (g[j][i]) j=g[j][i];                dl[++tail]=g[k][i];                fail[g[k][i]]=j;            }    }}void calc(int fh){    fo(i,0,m)        fo(j,0,tot)            f[i][j]=0;    czy=1;    t=root;    fo(i,0,m-1){        if (czy)            fo(j,0,b[i+1]-1) (f[i+1][next[t][j]]+=1)%=mo;        t=next[t][b[i+1]];        if (bz[t]) czy=0;        fo(j,1,tot){            if (bz[j]) continue;            fo(k,0,9)                (f[i+1][next[j][k]]+=f[i][j])%=mo;        }    }    if (czy) (f[m][t]+=1)%=mo;    fo(i,1,tot)        if (!bz[i]) (ans+=f[m][i]*fh)%=mo;}int main(){    //freopen("data.in","r",stdin);//freopen("wzd.out","w",stdout);    scanf("%s",s+1);    n=strlen(s+1);    a[m=1]=get()-'0';    while (1){        ch=getchar();        if (ch<'0'||ch>'9') break;        a[++m]=ch-'0';    }    fo(i,1,m) b[i]=get()-'0';    fo(i,1,m) c[i]=a[i],d[i]=b[i];    t=1;    fd(i,m,1){        if (d[i]<c[i]){            d[i]+=10;            d[i-1]--;        }        (num+=(ll)t*(d[i]-c[i])%mo)%=mo;        t=(ll)t*10%mo;    }    (num+=1)%=mo;    root=tot=1;    fo(i,1,n-(m/2)+1){        fo(j,i,i+(m/2)-1) h[j-i+1]=s[j];        insert(root,1);    }    prepare();    calc(1);    fo(i,1,m) b[i]=a[i];    b[m]--;    i=m;    while (b[i]<0){        b[i]+=10;        b[i-1]--;        i--;    }    calc(-1);    (num-=ans)%=mo;    (num+=mo)%=mo;    printf("%d\n",num);    /*fo(i,1,tot){        fo(j,0,9) printf("%d ",next[i][j]);        printf("\n");    }*/}
0 0
原创粉丝点击