首先感谢某些大神帮我解决此题
我们可以把所有的长度为前缀,后缀建字典树
对于字典树深度为k的节点,可以合并在这个节点上的字符串
那么这样想,一个字符串连接的是字典树的两个节点(自己的前缀和后缀),然后对于字符串连的每一条边,都至少有一个点要被选中
那么相当于在一张图上跑最小点覆盖集
此时我就不会了。。。跑去问,然后得到回复“这是一张二分图”
为什么呢?我们可以把所有前缀放在一边,后缀放在另外一边,分开建字典树
每一个字符串当做一条边,连接自己的前缀和后缀
这样就变成二分图了,跑最大匹配(其实是最小点覆盖)就好了
网络流反边写挂,wa*2
代码
//Copyright(c)2016 liuchenrui
#include<bits/stdc++.h>
#define inf 1000000000
using namespace std;
inline void splay(int &v){
v=0;char c=0;int p=1;
while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
v*=p;
}
struct Edge{
int to,next;int flow;
}edge[100010];
int first[10005],size;
int deep[10005],dl[10005];
void addedge(int x,int y,int z){
size++;
edge[size].to=y;
edge[size].next=first[x];
first[x]=size;
edge[size].flow=z;
}
void add(int x,int y,int z){
addedge(x,y,z),addedge(y,x,0);
//if(z)printf("%d %d\n",x,y);
}
int aim;
int dfs(int now,int flow){
if(now==aim)return flow;
int F=0;
for(int u=first[now];u&&flow;u=edge[u].next){
if(deep[edge[u].to]==deep[now]+1&&edge[u].flow){
int tmp=dfs(edge[u].to,min(flow,edge[u].flow));
F+=tmp;edge[u].flow-=tmp;edge[u^1].flow+=tmp;flow-=tmp;
}
}
if(!F)deep[now]=-5;
return F;
}
bool bfs(int S,int T){
memset(deep,0,sizeof(deep));
dl[1]=S;deep[S]=1;
int head=0,tail=1;
while(head!=tail){
head++;
for(int u=first[dl[head]];u;u=edge[u].next){
if(!deep[edge[u].to]&&edge[u].flow){
dl[++tail]=edge[u].to;
deep[edge[u].to]=deep[dl[head]]+1;
}
}
}
return deep[T];
}
int maxflow(int S,int T){
int ret=0;aim=T;
while(bfs(S,T)){
ret+=dfs(S,inf);
}
return ret;
}
int n,k;
struct Trie{
int t[1500000][26],tot;
int a[10010];map<int,int>f;
int insert(char *s,int id){
int now=0;
for(int i=1;i<=k;i++){
if(!t[now][s[i]-'A']){
t[now][s[i]-'A']=++tot;
}
now=t[now][s[i]-'A'];
}
f[now]=1;a[id]=now;
}
void ls(){
int cnt=0;
for(map<int,int>::iterator it=f.begin();it!=f.end();++it){
it->second=++cnt;
}
for(int i=1;i<=n;i++)a[i]=f[a[i]];
}
}A,B;
char s[100010];
int main(){
freopen("heavy.in","r",stdin);
freopen("heavy.out","w",stdout);
splay(n),splay(k);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
A.insert(s,i);
int len=strlen(s+1);
reverse(s+1,s+len+1);
B.insert(s,i);
}
A.ls(),B.ls();size=1;
int x=A.f.size(),y=B.f.size();
int S=0,T=x+y+1;
for(int i=1;i<=x;i++){
add(S,i,1);
}
for(int i=1;i<=y;i++){
add(i+x,T,1);
}
for(int i=1;i<=n;i++){
add(A.a[i],B.a[i]+x,1);
}
//cerr<<x<<" "<<y<<endl;
printf("%d\n",maxflow(S,T));
}