题目链接:https://www.luogu.com.cn/problem/CF590E
n n n个字符串,求一个最大的集合使其中没有任何串是其他集合内字符串的子串
先用 A C AC AC自动机建立好 f a i l fail fail树+传递闭包就可以确定好两两之间的子串关系了,之后用网络流最大匹配求最大独立集即可
#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
#include
#include
#include
#include
using namespace std;
const int N=1e7+10,M=1600,inf=2147483647/3;
struct node{
int to,next,w;
}a[1010000];
int n,tot=1,cnt,s,t;
int ch[N][2],fail[N],fa[N],cur[M];
int ls[M],ed[N],pos[N],dep[M];
bool d[M][M];char st[N];
queue<int> q;
void Make(char *s,int num){
int x=1,len=strlen(s);
for(int i=0;i<len;i++){
int w=s[i]-'a';
if(!ch[x][w])
ch[x][w]=++cnt,fa[cnt]=x;
x=ch[x][w];
}
ed[x]=num;pos[num]=x;
return;
}
void Bfs(){
ch[0][0]=ch[0][1]=1;
q.push(1);fail[1]=0;
while(!q.empty()){
int x=q.front();q.pop();
for(int i=0;i<2;i++)
if(!ch[x][i])ch[x][i]=ch[fail[x]][i];
else{
q.push(ch[x][i]);
int y=fail[x];
fail[ch[x][i]]=ch[y][i];
}
}
return;
}
void addl(int x,int y,int w)
{
a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;a[tot].w=w;
a[++tot].to=x;a[tot].next=ls[y];ls[y]=tot;a[tot].w=0;
}
bool bfs()
{
memset(dep,0,sizeof(dep));
memcpy(cur,ls,sizeof(cur));
while(!q.empty()) q.pop();
q.push(s);dep[s]=1;
while(!q.empty())
{
int x=q.front();q.pop();
for(int i=ls[x];i;i=a[i].next)
{
int y=a[i].to;
if(!dep[y]&&a[i].w){
dep[y]=dep[x]+1;
q.push(y);
}
}
}
if(dep[t]) return true;
return false;
}
int dinic(int x,int flow)
{
int rest=0,k;
if(x==t||!flow) return flow;
for(int i=cur[x];i;i=a[i].next)
{
int y=a[i].to;cur[x]=i;
if(dep[x]+1==dep[y]&&a[i].w)
{
rest+=(k=dinic(y,min(a[i].w,flow-rest)));
a[i].w-=k;a[i^1].w+=k;
if(rest==flow) return flow;
}
}
if(!rest) dep[x]=0;
return rest;
}
int main()
{
scanf("%d",&n);cnt=1;
for(int i=1;i<=n;i++){
scanf("%s",st);
Make(st,i);
}
Bfs();ed[1]=-1;
for(int i=1;i<=n;i++){
for(int j=pos[i];j!=1;j=fa[j]){
int x=fail[j];
while(!ed[x])x=fail[x];
int y=fail[j];
while(!ed[y]){
int w=fail[y];
fail[y]=x;y=w;
}fail[j]=x;
if(j!=pos[i]&&ed[j])d[i][ed[j]]=1;
if(x!=1)d[i][ed[x]]=1;
}
}
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
d[i][j]|=d[i][k]&d[k][j];
s=0;t=2*n+1;
for(int i=1;i<=n;i++)
addl(s,i,1),addl(i+n,t,1);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i!=j&&d[i][j])
addl(i,j+n,1);
int ans=n;
while(bfs())
ans-=dinic(s,inf);
printf("%d\n",ans);
for(int i=1;i<=n;i++)
if(dep[i]&&!dep[i+n])
printf("%d ",i);
return 0;
}