您的位置:首页 > Web前端 > JavaScript

bzoj 4460 : [Jsoi2013]广告计划

2016-05-26 18:11 232 查看
脑残一下午

首先,对于所有字符串建立后缀自动机

这里可以是广义后缀自动机或者狭义后缀自动机,我会给出2份代码

然后是匹配时间

我们枚举答案,问题变成一个答案是否能够被成功匹配

观察发现,如果当前答案为ans,那么1,1+ans,1+ans∗2......都会在一排一起出现

同理 2,2+ans,2+ans∗2......也会这样

我们定义have[i][j]表示i,i+ans,i+ans∗2......是否在第j列出现

这个可以在后缀自动机上求right集合实现

那么ans什么情况会成为答案呢?

我们观察样例,have[1][2],have[2][3],have[3][3]同时存在的时候,ans为答案

结论:ans为答案,仅当存在一个x,使得have[1][x],have[2][x],have[3][x]....have[ans][x]同时存在,但是存在例外:x有一次机会在中间某个地方+1

然后暴力跑就好了,由于我复杂度没有卡满所以跑得飞快QAQ

顺便说一句,两份代码统计right的方法是一样的,可以互换,但是有基数排序的方法

代码

狭义后缀自动机

#include<bits/stdc++.h>
#define N 20005
using namespace std;
namespace sam{
int last=1,tot=1;
int t
[27],pre
,val
,deep
;
bitset<102>right
;
void insert(int x,int ps){
int np=++tot,now=last;last=np;val[tot]=1;
deep[np]=deep[now]+1;right[np][ps]=1;
while(now&&!t[now][x]){
t[now][x]=np;now=pre[now];
}
if(!now)pre[np]=1;
else{
int q=t[now][x],p=now;
if(deep[p]+1==deep[q])pre[np]=q;
else{
int nq=++tot;deep[nq]=deep[p]+1;
pre[nq]=pre[q];pre[np]=pre[q]=nq;
memcpy(t[nq],t[q],sizeof t[q]);right[nq]=right[q];
while(now&&t[now][x]==q)t[now][x]=nq,now=pre[now];
}
}
}
struct node{
int id,x;
friend bool operator < (const node &a,const node &b){
return a.x<b.x;
}
}s
;
void add(){
for(int i=1;i<=tot;i++)s[i]=(node){i,deep[i]};
sort(s+1,s+tot+1);
for(int i=tot;i>=2;i--){
right[pre[s[i].id]]|=right[s[i].id];
}
}
}
char p[205];
int n,m,len;
bitset<102>have[205];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",p+1);
for(int j=1;j<=m;j++){
sam::insert(p[j]-'a',j);
}
sam::insert(26,0);
}
sam::add();
scanf("%s",p+1);len=strlen(p+1);
for(int ans=1;ans<=len;ans++){
for(int j=1;j<=ans;j++){
int x=1,y=j,f=0;
while(y<=len){
x=sam::t[x][p[y]-'a'];
y=y+ans;f++;
}
have[j]=sam::right[x]>>(f-1);
}
for(int i=1;i<=m;i++){
if(!have[1][i])continue;
int a=1,b=1;
for(int j=2;j<=ans;j++){
b=(a|b)&&have[j][i+1];
a&=have[j][i];
if((!a)&&(!b))break;
}
if(a|b)cout<<ans<<endl,exit(0);
}
}
}


广义后缀自动机

#include<bits/stdc++.h>
#define N 20005
using namespace std;
namespace sam{
int last=1,tot=1;
int t
[27],pre
,val
,deep
;
bitset<102>right
;
void insert(int x,int ps){
if(t[last][x]){
last=t[last][x];right[x][ps]=1;return;
}
int np=++tot,now=last;last=np;val[tot]=1;
deep[np]=deep[now]+1;right[np][ps]=1;
while(now&&!t[now][x]){
t[now][x]=np;now=pre[now];
}
if(!now)pre[np]=1;
else{
int q=t[now][x],p=now;
if(deep[p]+1==deep[q])pre[np]=q;
else{
int nq=++tot;deep[nq]=deep[p]+1;
pre[nq]=pre[q];pre[np]=pre[q]=nq;
memcpy(t[nq],t[q],sizeof t[q]);right[nq]=right[q];
while(now&&t[now][x]==q)t[now][x]=nq,now=pre[now];
}
}
}
int nxt
,fir
,to
,Sz;
void add(int x,int y){
nxt[++Sz]=fir[x];fir[x]=Sz;to[Sz]=y;
}
void dfs(int x){
for(int u=fir[x];u;u=nxt[u]){
dfs(to[u]);right[x]|=right[to[u]];
}
}
void add(){
for(int i=2;i<=tot;i++)add(pre[i],i);
dfs(1);
}
}
char p[205];
int n,m,len;
bitset<102>have[205];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",p+1);
for(int j=1;j<=m;j++){
sam::insert(p[j]-'a',j);
}
sam::last=1;
}
sam::add();
scanf("%s",p+1);len=strlen(p+1);
for(int ans=1;ans<=len;ans++){
for(int j=1;j<=ans;j++){
int x=1,y=j,f=0;
while(y<=len){
x=sam::t[x][p[y]-'a'];
y=y+ans;f++;
}
have[j]=sam::right[x]>>(f-1);
}
for(int i=1;i<=m;i++){
if(!have[1][i])continue;
int a=1,b=1;
for(int j=2;j<=ans;j++){
b=(a|b)&&have[j][i+1];
a&=have[j][i];
if((!a)&&(!b))break;
}
if(a|b)cout<<ans<<endl,exit(0);
}
}
}

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