自动机板子+数位即可
题意概要:
定义长度为的字符串为字符串的半匹配串,当且仅当内存在长度至少为的子串,使得其为的子串。
给出一个字符串,两个长度都为的十进制整数字符串和,求区间中有多少个数字字符串是的半匹配串。
输入的第一行为,第二行为,第三行为。和不含前导零。
数据保证,。
请将答案对取模。
自动机来处理匹配串。
数位来实现数字区间内的转化和推导。
实现见代码:
xxxxxxxxxx#include <bits/stdc++.h>using namespace std;#define LL long long#define N 33333#define mod 1000000007LL DP[2][N][2];int E[N],tot=0,tt;char C[1111];char A[55],B[55];int n;struct AC_Automaton{ //AC自动机模板,几乎没有更改,所以不解释int trans[N][10],fail[N],cur=0;int q[N],head,tail;void build_trie(){int m=strlen(C+1),l=n/2;for (int i=1;i+l-1<=m;i++){int p=0;for (int j=i;j<=i+l-1;j++){int k=C[j]-'0';if (!trans[p][k]) trans[p][k]=++cur;p=trans[p][k];}E[++tot]=p;}}void AC_build(){head=tail=0;for (int i=0;i<10;i++)if (trans[0][i])q[tail++]=trans[0][i];while (head<tail){int u=q[head++];for (int i=0;i<10;i++){if (trans[u][i]){int son=trans[u][i],p=fail[u];son=trans[u][i];while (p && !trans[p][i]) p=fail[p];fail[son]=trans[p][i];q[tail++]=son;}}}}}AC;LL Dightal_DP(char* c){ //数位DP部分memset(DP,0,sizeof(DP));int pp=0;tt=0;int now=0,last=1;for (int i=1;i<=n;i++){swap(now,last);memset(DP[now],0,sizeof(DP[now]));for (int j=0;j<=AC.cur;j++){ //递推核心部分for (int k=0;k<10;k++){int p=j;while (!AC.trans[p][k] && p) p=AC.fail[p];p=AC.trans[p][k];DP[now][p][0]+=DP[last][j][0];if (DP[now][p][0]>=mod) DP[now][p][0]-=mod;DP[now][p][1]+=DP[last][j][1];if (DP[now][p][1]>=mod) DP[now][p][1]-=mod;}}for (int k=0;k<c[i]-'0';k++){ //继续寻找下一个匹配串int p=pp;while (!AC.trans[p][k] && p) p=AC.fail[p];p=AC.trans[p][k];DP[now][p][tt]++;if (DP[now][p][tt]>=mod) DP[now][p][tt]-=mod;}int k=c[i]-'0'; //当前节点是pp,如果不能往k儿子走,就往fail跳while (!AC.trans[pp][k] && pp) pp=AC.fail[pp]; //跳出循环时,要么找到了一个有k儿子的后缀节点,要么跳回了根节点pp=AC.trans[pp][k];for (int j=1;j<=tot;j++){DP[now][E[j]][1]+=DP[now][E[j]][0];DP[now][E[j]][0]=0;if (DP[now][E[j]][1]>=mod) DP[now][E[j]][1]-=mod;if (E[j]==pp) tt=1;}}LL ret=tt;for (int i=0;i<=AC.cur;i++){ret+=DP[now][i][1];if (ret>=mod) ret-=mod;}return ret;}int main(){scanf("%s",C+1); //读入scanf("%s",A+1);scanf("%s",B+1);n=strlen(A+1);AC.build_trie(); //建出AC自动机AC.AC_build();LL ans=Dightal_DP(B)-Dightal_DP(A);ans+=tt;if (ans<0) ans+=mod;cout<<ans<<endl; //输出return 0;}