链接:http://codeforces.com/contest/590/problem/E
题意:给出n(n<=750)个字符串,要求从中选出尽可能多的串,使得两两不是包含关系,并输出方案。(串长不超过
107
)
用AC自动机处理包含关系之后,题目转化为求最长反链,并输出方案。关于DAG的最长反链,可以参考这个,然而本题的难点在于输出方案。结论是:最小点覆盖的补集就是最长反链的方案。首先,由于最小点覆盖的补集大小=最长反链的大小,因此,只要证明这个补集是一个反链即可。而这是显然的,因为假如这不是一个反链,必然存在一对u,v,满足u,v不在点覆盖中,但是u,v之间有边,这就表明那并不是一个点覆盖,产生矛盾。
值得注意的是原有向无环图必须先求一边传递闭包,否则上述并不成立。
因此,只需要输出一种最小点覆盖的方案即可。自己yy了一种求点覆盖的方法:
1.先令左边的匹配的点都是点覆盖中的点
2.对于每个左边的非匹配点,假如他连接着一条未被覆盖的边,那么就把对应的右点置为覆盖点,同时,由于这个右点必然是一个匹配点,要将他匹配的点移出覆盖点
3.由于被移除了覆盖点,有些非匹配边可能未被覆盖到,因此这时候递归的进行2即可
#include<bits/stdc++.h>
using namespace std;
const int Maxn=10000009;
int n;
string ss[755];
int ch[Maxn][2];
int f[Maxn],last[Maxn];
int val[Maxn],id[755];
int cnt,tot;//zong jie dian,zong chuan
void insert(int idx,string &s)
{
int rt=0;
for(int i=0;i<s.size();i++)
{
int c=s[i]-'a';
if(!ch[rt][c]){ch[rt][c]=cnt++;}
rt=ch[rt][c];
}
if(!val[rt]){val[rt]=++tot;id[tot]=idx;}
}
bool G[755][755];
int linkl[755],linkr[755];
bool done[755],isl[755],isr[755];
bool dfs(int u)
{
//printf("u=%d\n",u);
for(int i=1;i<=tot;i++)
{
if(!G[u][i]||done[i])continue;
done[i]=1;
if(!linkr[i]||dfs(linkr[i]))
{
linkr[i]=u;
return 1;
}
}
return 0;
}
void getf()
{
queue<int>q;
f[0]=0;
for(int c=0;c<2;c++)
{
int u=ch[0][c];
if(u){f[u]=0;q.push(u);last[u]=0;}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<2;c++)
{
int u=ch[r][c];
if(!u)continue;
q.push(u);
int v=f[r];
while(v&&!ch[v][c])v=f[v];
f[u]=ch[v][c];
last[u]=val[f[u]]?f[u]:last[f[u]];
}
}
}
void dfs2(int u)
{
for(int i=1;i<=tot;i++)
{
if(!G[u][i])continue;
if(!isr[i])
{
isr[i]=1;
isl[linkr[i]]=0;
dfs2(linkr[i]);
}
}
}
int main()
{
scanf("%d",&n);
cnt=1;
for(int i=1;i<=n;i++)
{
cin>>ss[i];
insert(i,ss[i]);
}
getf();
for(int i=1;i<=tot;i++)
{
int now=0;
string &s=ss[id[i]];
for(int j=0;j<s.size();j++)
{
int c=s[j]-'a';
now=ch[now][c];
if(j!=s.size()-1&&val[now])
{
G[i][val[now]]=1;
continue;
}
if(val[last[now]])
{
G[i][val[last[now]]]=1;
}
}
}
for(int i=1;i<=tot;i++)
for(int j=1;j<=tot;j++)
for(int k=1;k<=tot;k++)
{
if(G[j][i]&&G[i][k])G[j][k]=1;
}
/*
for(int i=1;i<=tot;i++)
{
for(int j=1;j<=tot;j++)
printf("%d ",G[i][j]);
puts("");
}
*/
int ans=0;
for(int i=1;i<=tot;i++)
{
memset(done,0,sizeof(done));
//printf("i=%d\n",i);
if(dfs(i))ans++;
}
//printf("ans=%d\n",ans);
for(int i=1;i<=tot;i++)
if(linkr[i])
linkl[linkr[i]]=i;
for(int i=1;i<=tot;i++)
if(linkl[i])isl[i]=1;
//for(int i=1;i<=tot;i++)printf("%d ",linkr[i]);puts("");
for(int i=1;i<=tot;i++)
{
if(!linkl[i])
{
dfs2(i);
}
}
vector<int>rep;
for(int i=1;i<=tot;i++)if(!isl[i]&&!isr[i])rep.push_back(i);
printf("%d\n",(int)rep.size());
for(int i=0;i<rep.size();i++)
printf("%d%c",rep[i],i==rep.size()?'\n':' ');
}