[51nod1587]半现串

将s所有长度为d/2的子串放进ac自动机中,直接匹配就可以判定半现串了
再对其做一个差分,询问一个前缀的半现串个数,在ac自动机上数位dp,f[i][j][0/1]表示走了i步(i位的字符串),走到节点j,是否达到上限的方案数
对于ac自动机上的结束节点,直接重置并累计答案即可

 1 #include
 2 using namespace std;
 3 #define N 1005
 4 #define c (s[i]-'0')
 5 #define mod 1000000007
 6 queue<int>q;
 7 int V,n,d,ans,mi[51],mo[51],vis[N*50],nex[N*50],ch[N*50][11],f[51][N*50][2];
 8 char s[N],s1[51],s2[51];
 9 void add(int l,int r){
10     int k=0;
11     for(int i=l;i<=r;i++){
12         if (!ch[k][c])ch[k][c]=++V;
13         k=ch[k][c];
14     }
15     vis[k]=1;
16 }
17 void build(){
18     for(int i=0;i<10;i++)
19         if (ch[0][i])q.push(ch[0][i]);
20     while (!q.empty()){
21         int k=q.front();
22         q.pop();
23         for(int i=0;i<10;i++)
24             if (!ch[k][i])ch[k][i]=ch[nex[k]][i];
25             else{
26                 nex[ch[k][i]]=ch[nex[k]][i];
27                 q.push(ch[k][i]);
28             }
29     }
30 }
31 int query(char *s){
32     ans=0;
33     memset(f,0,sizeof(f));
34     mi[0]=mo[d]=f[0][0][1]=1;
35     for(int i=1;i<=d;i++)mi[i]=10LL*mi[i-1]%mod;
36     for(int i=d-1;i>=0;i--)mo[i]=(mo[i+1]+1LL*c*mi[d-i-1])%mod;
37     for(int i=0;i)
38         for(int j=0;j<=V;j++){
39             if (vis[j])continue;
40             for(int k=0;k<10;k++){
41                 int p=ch[j][k];
42                 f[i+1][p][0]=(f[i+1][p][0]+f[i][j][0])%mod;
43                 if (k<=c)f[i+1][p][k==c]=(f[i+1][p][k==c]+f[i][j][1])%mod;
44             }
45         }
46     for(int i=0;i<=d;i++)
47         for(int j=0;j<=V;j++)
48             if (vis[j])
49                 ans=(ans+1LL*f[i][j][0]*mi[d-i]+1LL*f[i][j][1]*mo[i])%mod;
50     return ans;
51 }
52 int main(){
53     scanf("%s%s%s",s,s1,s2);
54     n=strlen(s);
55     d=strlen(s1);
56     V=0;
57     for(int i=0;i<=n-d/2;i++)add(i,i+d/2-1);
58     build();
59     ans=(query(s2)-query(s1)+mod)%mod;
60     for(int i=0,k=0;s1[i];i++){
61         k=ch[k][s1[i]-'0'];
62         if (vis[k]){
63             ans=(ans+1)%mod;
64             break;
65         }
66     }
67     printf("%d",ans);
68 }
View Code

 

你可能感兴趣的:([51nod1587]半现串)