您的位置:首页 > 其它

5332. 【NOIP2017提高A组模拟8.23】密码 AC自动机+数位DP

2017-08-23 20:35 495 查看
题意:求x-y之间有多少个数字包含至少k个密钥,密钥给出,x-y的数位比500小。

老年选手,这种题都不会做了,我退群吧。

就是随便AC自动机dp啊。。。我太废了。

设f[i][j][k][0/1]表示匹配到串的第i个节点,AC自动机上跑到了j,已经匹配了k个密钥,

0/1表示我之前匹配的哪些数位是否完全匹配某些密钥。

所以1可以转化为1或0,0只能转化0,然后xjbDP就好。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=505;
const int mo=1e9+7;
int n,k,cnt;
queue<int> q;
int ch
[12];
int val
,f

[15][2];
int fail
;
char x
,y
,s
;
inline void ins()
{
int len=strlen(s),x=0;
fo(i,0,len-1)
{
char c=s[i]-'0';
if (ch[x][c])x=ch[x][c];
else x=ch[x][c]=++cnt;
}
val[x]++;
}
inline void getfail()
{
fo(i,0,9)
if(ch[0][i])q.push(ch[0][i]);
while (!q.empty())
{
int x=q.front();
q.pop();
fo(i,0,9)
if (!ch[x][i])ch[x][i]=ch[fail[x]][i];
else
{
q.push(ch[x][i]),
fail[ch[x][i]]=ch[fail[x]][i];
val[ch[x][i]]+=val[fail[ch[x][i]]];
}
}
}
inline int solve(char *a)
{
int len=strlen(a+1);
memset(f,0,sizeof(f));
f[0][0][0][1]=1;
fo(i,0,len-1)
fo(j,0,cnt)
fo(l,0,k)
{
if (f[i][j][l][0])
fo(c,0,9)
{
int tmp=min(k,l+val[ch[j][c]]);
(f[i+1][ch[j][c]][tmp][0]+=f[i][j][l][0])%=mo;
}
if (f[i][j][l][1])
{
int s1=a[i+1]-'0';
int tmp=min(k,l+val[ch[j][s1]]);
(f[i+1][ch[j][s1]][tmp][1]+=f[i][j][l][1])%=mo;

fo(c,0,s1-1)
{
tmp=min(k,l+val[ch[j][c]]);
(f[i+1][ch[j][c]][tmp][0]+=f[i][j][l][1])%=mo;
}

}
}
int ans=0;
fo(i,0,cnt)(ans+=(f[len][i][k][0]+f[len][i][k][1])%mo)%=mo;
return ans;
}
int main()
{
freopen("word.in","r",stdin);
freopen("word.out","w",stdout);
scanf("%d%d%s%s",&n,&k,x+1,y+1);
fo(i,1,n)
{
scanf("%s",s);
ins();
}
getfail();
printf("%d\n",(solve(y)-solve(x)+mo)%mo);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: