您的位置:首页 > 其它

[51nod 1587]半现串

2017-01-12 20:26 267 查看

题目描述

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1587

AC自动机上的DP

把S所有长度是d/2的提出来造个AC自动机。

然后做数位DP,用一维状态表示匹配到AC自动机上哪个节点。

匹配成功状态不要转移。

于是可以计算出不匹配的数量。

#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");
}*/
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: