您的位置:首页 > 其它

2017.8.14 文本生成器 失败总结

2017-08-14 19:24 148 查看
        以后凡是在一个中出现>=1次的题就直接转0次用容斥好了、  

        然后剩下的就是怎么找一个单词也不出现的文本的个数了

        显然,这种计数类问题需要用dp  ,而且我们需要知道所有单词会为我们添加字母造成影响,所以需要用ac自动机,跳过所有标记的单词 

           以前是写的指针ac自动机,但它不好写而且巨慢、 所以换了数组

           要注意用0表示null   1表示root   为了方便,我们将0的所有下一个赋为root    同时这个失配指针是指向最近的和自己相同的字母   root可表示所有字母..

           而且失配是单词这个点也不能取,,因为

    


       然后sp数组开小了溢出导致f数组储存信息错误、、查了1.5h才查出来

码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
queue<int>q;
int sz=1,ans1,ans2,n,m,i,j,sp[7000],ch[7000][27],dc[7000],f[105][7000];
char str[105];
#define P 10007
void ins()
{
int l=strlen(str),i,o=1;
for(i=0;i<l;i++)
{
int zm=str[i]-'A'+1;
if(ch[o][zm])o=ch[o][zm];
else o=ch[o][zm]=++sz;
}
dc[o]=1;
}
void shipei()
{
int i;sp[1]=0;
q.push(1);
while(!q.empty())
{
int st=q.front();
q.pop();
for(i=1;i<=26;i++)
{
if(ch[st][i]==0)continue;
int k=sp[st];
while(!ch[k][i])
k=sp[k];
sp[ch[st][i]]=ch[k][i];
if(dc[ch[k][i]])dc[ch[st][i]]=1;
q.push(ch[st][i]);
}
}
}
void dp(int x)
{
int i,j;
for(i=1;i<=sz;i++)
{
if(dc[i]||!f[x-1][i])continue;
for(j=1;j<=26;j++)
{
int k=i;
while(!ch[k][j])k=sp[k];
f[x][ch[k][j]]= (f[x][ch[k][j]] +f[x-1][i] )%P;//if(x<2)cout<<f[x][ch[k][j]]<<" ";
}
}
}
int main()
{
ans2=1;
scanf("%d%d",&n,&m) ;
for(i=1;i<=26;i++)ch[0][i]=1;
f[0][1]=1;
for(i=1;i<=n;i++)
{
scanf("%s",str);
ins();
}
shipei();
for(i=1;i<=m;i++)dp(i);
for(i=1;i<=m;i++)ans2=(ans2*26)%P;
for(i=1;i<=sz;i++)if(!dc[i])ans1=(ans1+f[m][i])%P;
printf("%d",(ans2-ans1+P)%P);
}

   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: