#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. Python3.6下使用会话session保持登陆状态

    本次工具主要利用python easygui模块的inputbox让用户首次输入登陆信息,作为网站requests-post请求的data字段,观察XHR(异步加载)的数据包,构造post请求,利用r ...

  2. [Java in NetBeans] Lesson 00. Getting Set-up for Learning Java

    这个课程的参考视频在youtube. 主要学到的知识点有: set up needs Java SE JDK, NetBeans IDE class name should be the same l ...

  3. 启动及更改tomcat 配置

    到tomcat安装的bin目录下面,双击那个startup.bat文件,启动Tomcat 去浏览器输入 http://localhost:8080/  然后出现下面的界面,那就说明你的tomcat配置 ...

  4. android 通过页面上关键字快速定位代码

    这里定位微信关于页面, 当然可以直接获取当前最顶层activity 反编译apk后 搜索 strings.xml,找到对应id 搜索文件到用到id对应的成员变量,通常 是在R*.smali文件中 字符 ...

  5. 多模块项目提示“Module ** must not contain source root **. The root already belongs to module **”的解决办法

    从Project Structure里添加模块,完了点击Apply时弹出提示: Module "paycode"must not contain source root " ...

  6. linux telnet命令

    telnet命令通常用来远程登录.telnet程序是基于TELNET协议的远程登录客户端程序.Telnet协议是TCP/IP协议族中的一员,是Internet远程登陆服务的标准协议和主要方式.它为用户 ...

  7. js执行上下文

    js在执行是会有一个“准备工作”: 主要内容有 1.变量.函数表达式——>变量声明,默认赋值为undefined: 2.this——>赋值: 3.函数声明——>赋值: 这三种数据的准 ...

  8. UI界面之淡入淡出

    1.using UnityEngine; using System.Collections; using UnityEngine.UI; public class danrudanchu : Mono ...

  9. Delegate,Action,Func,匿名方法,匿名委托,事件

    一.委托Delegate 一般的方法(Method)中,我们的参数总是string,int,DateTime...这些基本的数据类型(或者没有参数),比如 public void HelloWorld ...

  10. 变量part2

    一 变量值具有三个特征:  1. id:变量值的唯一编号,内存地址不同id则不同  2. type:类型  3. value(值) #name='xia' #print(id(name)) #age= ...