#180. 「2019冬令营提高组」不同的缩写

乍看之下没有什么好的方法鸭.......于是考虑暴力。

长度?二分似乎可行。

于是我们二分最长子串的长度(设为$len$),蓝后暴力查找。

先在每个串内练好后继边建图

for(int i=;i<=n;++i){
int len=strlen(a[i]+);
for(int j=;j<;++j) To[i][len][j]=-;
for(int j=len-;j>=;--j){
memcpy(To[i][j],To[i][j+],sizeof(To[i][j+]));
To[i][j][a[i][j+]-'a']=j+;
}
}

每次用dfs查找一个串中长度不超过$len$的子串个数。

一个重要的剪枝:当长度不超过$len$的子串个数已经超过n个时,显然我们可以停止查找。因为显然无论怎么配,这个串都有解。

现在,我们筛掉了一定有解的串,那么对于剩下的串我们怎么判断答案为$len$时是否有解?

考虑暴力建出一棵trie树,保存剩下串的信息。

接下来我们实现匹配

首先我们先新建总起点,终点$S,T$;以及$n-w$个点表示对应的子串(前面剪枝剪掉的子串(设为$w$个)就不用建点辣)

(当然你可以方便地直接开n个点)

我们遍历子串$k$,当访问到树上的某个节点$p$时,从$k$向$p$连一条流量为1的边(没错!我们等下要跑网络流),表示一种匹配。

所有串遍历完后,trie上的每个点都向$T$连一条流量为1的边。

最后,$S$向$n-w$个代表子串的点连一条流量为1的边。

于是我们就可以从$S$到$T$愉快地跑一遍dinic辣


找到了最短的长度,现在考虑输出其中一种方案。

直接上dfs遍历每一个串,如果找到一个还未打上结束标记的节点,就把这个节点的结束标记打上该串的编号,然后跳出dfs,遍历下个串。

最后开个字符栈,再跑遍dfs。

蓝后就是艰难(for me)的打code了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define stop system("pause")
using namespace std;
inline int min(int a,int b){return a<b?a:b;}
const int inf=;
#define N 305
#define M 500005
char a[N][N]; bool vis[M];
int n,ans=-,To[N][N][],tot,is[N];
int d[M],cur[M],S,T;
int tri,p[M][],fr[M];
int cnt,hd[M],nxt[M],ed[M],poi[M],cap[M];
queue <int> h;
string b,name[N];
void clear(int x){for(int i=;i<;++i)p[x][i]=;}
void add(int x,int y,int v){
nxt[ed[x]]=++cnt; hd[x]=hd[x]?hd[x]:cnt;
ed[x]=cnt; poi[cnt]=y; cap[cnt]=v;
}
void ins(int x,int y,int v){add(x,y,v);add(y,x,);}
#define to poi[i]
bool bfs(){
memset(vis,,sizeof(vis));
memset(d,-,sizeof(d));
h.push(S); vis[S]=; d[S]=;
while(!h.empty()){
int x=h.front(); h.pop();
for(int i=hd[x];i;i=nxt[i]){
if(!vis[to]&&cap[i]>){
vis[to]=;
d[to]=d[x]+;
h.push(to);
}
}
}return vis[T];
}
int dfs(int x,int a){//dinic
if(x==T||a==) return a;
int F=,f;
for(int &i=cur[x];i&&a>;i=nxt[i])
if(d[to]==d[x]+&&(f=dfs(to,min(cap[i],a)))>)
cap[i]-=f,a-=f,cap[i^]+=f,F+=f;
return F;
}
int dinic(){
int re=;
while(bfs()){
for(int i=;i<=tri+;++i) cur[i]=hd[i];
re+=dfs(S,inf);
}
return re;
}
void dfs1(int d,int id,int o,int dl){
if(d) ++tot;
if(d==dl||tot>=n) return;
for(int i=;i<&&tot<n;++i)
if(To[id][o][i]!=-)
dfs1(d+,id,To[id][o][i],dl);
}
void dfs2(int d,int id,int o,int dl,int u){
if(d) ins(id,u,);
if(d==dl) return;
for(int i=;i<;++i)
if(To[id][o][i]!=-){
if(!p[u][i]) p[u][i]=++tri,clear(tri);
dfs2(d+,id,To[id][o][i],dl,p[u][i]);
}
}
bool chk(int lim){
memset(ed,,sizeof(ed));
memset(hd,,sizeof(hd));
memset(nxt,,sizeof(nxt));
cnt=; tri=n+; clear(n+);
for(int i=;i<=n;++i){
tot=; is[i]=;
dfs1(,i,,lim);
if(tot<n) is[i]=,dfs2(,i,,lim,n+);//剪枝
}S=tri+;T=tri+;
int tflow=;
for(int i=;i<=n;++i)
if(is[i]) ++tflow,ins(S,i,);
for(int i=n+;i<=tri;++i) ins(i,T,);
return tflow==dinic();
}
int dfs3(int d,int id,int o,int dl,int u){
if(d&&!fr[u]){fr[u]=id; return ;}
if(d==dl) return ;
for(int i=;i<;++i)
if(To[id][o][i]!=-){
if(!p[u][i]) p[u][i]=++tri,clear(tri);
if(dfs3(d+,id,To[id][o][i],dl,p[u][i]))
return ;
}
return ;
}
void dfs4(int u){
if(fr[u]) name[fr[u]]=b;
for(int i=;i<;++i)
if(p[u][i]){
b+=(i+'a'); dfs4(p[u][i]);
b.erase(b.size()-);
}
}
int main(){
freopen("diff.in","r",stdin);
freopen("diff.out","w",stdout);
scanf("%d",&n);
for(int i=;i<=n;++i) scanf("%s",a[i]+);
for(int i=;i<=n;++i){
int len=strlen(a[i]+);
for(int j=;j<;++j) To[i][len][j]=-;
for(int j=len-;j>=;--j){
memcpy(To[i][j],To[i][j+],sizeof(To[i][j+]));
To[i][j][a[i][j+]-'a']=j+;
}
}
int l=,r=n;
while(l<r){
int mid=(l+r)/;
if(chk(mid)) r=mid;
else l=mid+;
}if(!chk(l)){printf("-1");return ;}
ans=l;
for(int i=;i<=n;++i)
if(is[i])
for(int j=hd[i];j;j=nxt[j])
if(cap[j]==)
fr[poi[j]]=i;
for(int i=;i<=n;++i)
if(!is[i]) dfs3(,i,,ans,n+);
b=""; dfs4(n+);
printf("%d\n",ans);
for(int i=;i<=n;++i) cout<<name[i]<<endl;
return ;
}

fjwc2019 D1T3 不同的缩写(dinic+trie+dfs)的更多相关文章

  1. 开篇,UVA 755 && POJ 1002 487--3279 (Trie + DFS / sort)

    博客第一篇写在11月1号,果然die die die die die alone~ 一道不太难的题,白书里被放到排序这一节,半年前用快排A过一次,但是现在做的时候发现可以用字典树加深搜,于是乐呵呵的开 ...

  2. bzoj 3439 Kpm的MC密码(Trie+dfs序+主席树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3439 [题意] 给定若干串,问一个串的作为其后缀的给定串集合中的第k小. [思路] 如 ...

  3. poj 1816 (Trie + dfs)

    题目链接:http://poj.org/problem?id=1816 思路:建好一颗Trie树,由于给定的模式串可能会重复,在原来定义的结构体中需要增加一个vector用来记录那些以该节点为结尾的字 ...

  4. 校内OJ 1128 词链(link)(Trie+DFS)

    1128: 词链(link) 时间限制: 1 Sec  内存限制: 64 MB 提交: 23  解决: 7 [提交][状态][讨论版] 题目描述 给定一个仅包含小写字母的英文单词表,其中每个单词最多包 ...

  5. BZOJ 3439: Kpm的MC密码( trie + DFS序 + 主席树 )

    把串倒过来插进trie上, 那么一个串的kpm串就是在以这个串最后一个为根的子树, 子树k大值的经典问题用dfs序+可持久化线段树就可以O(NlogN)解决 --------------------- ...

  6. 51nod1464(trie + dfs)

    题目链接: http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1464 题意: 中文题诶~ 思路: 将所有半回文串构建成一棵字 ...

  7. HDU 6191 Query on A Tree(可持久化Trie+DFS序)

    Query on A Tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Othe ...

  8. BZOJ-3439:Kpm的MC密码(Trie+DFS序+主席树)

    背景 想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的...),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身份验证问题了... 描述 ...

  9. BZOJ 3439: Kpm的MC密码 (trie+dfs序主席树)

    题意 略 分析 把串倒过来插进trietrietrie上, 那么一个串的kpmkpmkpm串就是这个串在trietrietrie上对应的结点的子树下面的所有字符串. 那么像 BZOJ 3551/354 ...

随机推荐

  1. mac xcode 常见配置

    1.报错:There are no schemes in workspace "..." 设置scheme共享,方法: 2.Build 文件夹是中间文件的保存地方,如何设置在工程目 ...

  2. [xdoj]1299&1300朱神的烦恼 朱神的序列

    http://acm.xidian.edu.cn/problem.php?id=1299 1.第一道题简单的很,数据范围最多只有1e4,对于数组中的每一个元素进行两个for循环,i=0;i<n; ...

  3. 第二章:Opencv核心類Mat

    Opecv就是做計算機視覺,就是讲图片转换成计算机所能识别的数据 Mat类中由大量的内联函数,主要就是用于提高速度. 一般类型都用rgb,存的时候用CV_8UC3.create函数一般会把原来的空间释 ...

  4. MySQL报错

    1,使用mysqldump导出数据报错: mysqldump: Error 2020: Got packet bigger than 'max_allowed_packet' bytes when d ...

  5. HDU 2254 奥运(矩阵+二分等比求和)

    奥运 [题目链接]奥运 [题目类型]矩阵+二分等比求和 &题解: 首先离散化城市,之后就是矩阵快速幂了,但让求的是A^(t1)+A^(t1+1)+...+A^(t2),我先想的是打表,但时间真 ...

  6. java数据结构和算法编程作业系列篇-数组

    /** * 编程作业 2.1 向highArray.java程序(清单2.3)的HighArray类添加一个名为getMax()的方法,它返回 数组中最大关键字的值,当数组为空时返回-1.向main( ...

  7. spark sql01

    package sql; import org.apache.spark.SparkConf; import org.apache.spark.api.java.JavaSparkContext; i ...

  8. Python记录2:数据类型

    一Python的数据类型可以分为可变与不可变两种: 可变类型:值改变,但是id不变,证明就是在改变原值,就是可变类型 如list   dict 列表和字典都是可变类型 不可变类型:值改变,id也跟着改 ...

  9. 排序(Sort)-----冒泡排序

    声明:文中动画转载自https://blog.csdn.net/qq_34374664/article/details/79545940    1.冒泡排序简介 冒泡排序(Bubble Sort),又 ...

  10. jQuery效果--show([speed,[easing],[fn]])和hide([speed,[easing],[fn]])

    hide([speed,[easing],[fn]]) 概述 隐藏显示的元素 这个就是 'hide( speed, [callback] )' 的无动画版.如果选择的元素是隐藏的,这个方法将不会改变任 ...