[P5254]「JSOI2013」『字符串哈希』『枚举』广告计划
可能更好的阅读体验
题目大意:有
考虑字符串哈希,将所有子串用27进制压缩存到哈希表中(即每个字符串的任意位置开头和任意位置结尾),同时记录每个串所在的字符串的编号和开头所在的位置。
从小到大枚举
如:
3个小串分别是
将这
若第
再枚举
也就是说,在这种情况下,如果一些
#include<cstdio>
#include<cstring>
#define md 2999999
#define hashmd 5100001
using namespace std;
int n,l,m,id,now,num,mi[105],pos[505001][2],nxt[505001],head[5100001],hs[5100001],bj[205][205],c[205][205];
bool flag;
char s[105][105],ss[205];
void add(int x,int i,int j)
{
pos[++num][0]=i;pos[num][1]=j;
nxt[num]=head[x];
head[x]=num;
}
void hash(int x,int i,int j)
{
int p=x;
while (hs[p])
{
if (hs[p]==x)
{
add(p,i,j);
return;
}
p=(p+1)%hashmd;
}
hs[p]=x;
add(p,i,j);
}
void find(int x,int r)
{
int p=x;
while (hs[p])
{
if (hs[p]==x)
{
for (int i=head[x];i;i=nxt[i])
c[r][pos[i][1]]=pos[i][0],bj[r][pos[i][1]]=id;
return;
}
p=(p+1)%hashmd;
}
}
int main()
{
mi[0]=1;
for (int i=1;i<=100;++i)
mi[i]=mi[i-1]*27%md;
scanf("%d%d",&n,&l);
for (int i=1;i<=n;++i)
{
scanf("%s",s[i]+1);
for (int j=1;j<=l;++j)
{
int x=1;
for (int k=j;k<=l;++k)
{
x=(x+(s[i][k]-'a'+1)*mi[k-j+1]%md)%md;
hash(x,i,j);
}
}
}
scanf("%s",ss+1);
m=strlen(ss+1);
for (int k=1;k<=m;++k)
{
++id;
for (int j=1;j<=k;++j)
{
int x=1,ln=0;
now=j;
while (now<=m)
{
x=(x+(ss[now]-'a'+1)*mi[++ln]%md)%md;
now+=k;
}
find(x,j);
}
for (int i=1;i<=k;++i)
{
int h=k-i+1;
for (int j=1;j<=l;++j)
{
flag=true;
for (int u=1;u<=k;++u)
{
if ((u<=h&&bj[u][j]<id)||(u>h&&bj[u][j+1]<id))
{
flag=false;
break;
}
}
if (flag)
{
printf("%d\n",k);
for (int u=h+1;u<=k;++u) printf("%d ",c[u][j+1]);
for (int u=1;u<=h;++u) printf("%d ",c[u][j]);
return 0;
}
}
}
}
printf("-1\n");
return 0;
}
感谢LZA的博客提供的帮助,ORZ:
https://blog.csdn.net/qq_39565901/article/details/87472261