博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
day16T3改错记
阅读量:4708 次
发布时间:2019-06-10

本文共 3490 字,大约阅读时间需要 11 分钟。

题目描述

\(n\)个串,你要把每个串用它的一个子序列(可以不连续)替换,使得最终不存在两个串相同,求替换后最长串的最小长度,以及替换方案

输入的串可能有相同的

\(n \le 300\),每个原串长度不超过\(300\)

解析

“最长的长度最小”套路二分

问题变成判断是否存在一种合法方案使得替换后所有串长度不超过\(mid\)

因为是用子序列替换,先建出子序列自动机

然后因为一个新串只能替换一个原串,所以考虑二分图

对每个原串,找出它的长度不超过的\(mid\)的子序列,并将原串同这个子序列代表的点连边

注意到如果长度满足条件的子序列不少于\(n\)个,那么这个原串一定可以匹配上一个新串,所以每个原串最多只需要找\(n\)个合法子序列就可以了

找出的所有新串构成一棵\(trie\)\(trie\)每个节点都对应了新串,所以点数不超过\(n^2\),可以用\(trie\)的点编号来表示新串

然后匈牙利或者\(dinic\)判断是否存在完备匹配

复杂度\(O(n^3\log maxlen)\)

代码

警告:代码极度丑陋,我自己都看不下去了,有时间再重构吧

#include 
#include
#include
#define MAXN 305typedef long long LL;struct Trie { int fa[MAXN * MAXN], trans[MAXN * MAXN][MAXN], ch[MAXN * MAXN], idx; int newnode(int = 0, int = 0); void init(); int insert(char *); void print(int);};struct Graph { struct Edge { int v, next; Edge(int _v = 0, int _n = 0):v(_v), next(_n) {} } edge[MAXN * MAXN]; int head[MAXN], cnt, pre[MAXN], link[MAXN * MAXN]; bool vis[MAXN * MAXN]; void init() { memset(head, -1, sizeof head); memset(link, -1, sizeof link); cnt = 0; } void add_edge(int u, int v) { edge[cnt] = Edge(v, head[u]); head[u] = cnt++; } bool match(int);};void prework();bool check(int);void dfs(int, int, int &, int, int, int);int N, next[MAXN][MAXN][26], len[MAXN], maxlen, endp[MAXN * MAXN], tot, top;char name[MAXN][MAXN], str[MAXN];Trie trie;Graph G;int main() { freopen("diff.in", "r", stdin); freopen("diff.out", "w", stdout); scanf("%d", &N); for (int i = 0; i < N; ++i) { scanf("%s", name[i] + 1); len[i] = strlen(name[i] + 1) + 1; maxlen = std::max(maxlen, len[i]); } prework(); int l = 1, r = maxlen; while (l < r) { int mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; } if (check(l)) { printf("%d\n", l); for (int i = 0; i < N; ++i) trie.print(G.pre[i]), putchar('\n'); } else puts("-1"); return 0;}void Trie::init() { idx = 0; newnode(); }int Trie::newnode(int f, int c) { ++idx; for (int i = 0; i < 26; ++i) trans[idx][i] = 0; fa[idx] = f, ch[idx] = c; return idx;}void Trie::print(int x) { if (fa[x] ^ 1) print(fa[x]); putchar('a' + ch[x]);}void prework() { for (int i = 0; i < N; ++i) for (int j = len[i] - 1; j >= 0; --j) for (int k = 0; k < 26; ++k) next[i][j][k] = (name[i][j + 1] - 'a' == k ? j + 1 : next[i][j + 1][k]);}bool check(int m) { G.init(); trie.init(); tot = N - 1; for (int i = 0; i < N; ++i) { int rest = N; dfs(i, 0, rest, m, 0, 1); } for (int i = 0; i < N; ++i) { memset(G.vis, 0, sizeof G.vis); if (!G.match(i)) return 0; } return 1;}void dfs(int id, int p, int &rest, int m, int dep, int cur) { if (!rest) return; if (dep == m) return; for (int i = 0; i < 26; ++i) if (next[id][p][i]) { if (!rest) break; --rest; if (!trie.trans[cur][i]) trie.trans[cur][i] = trie.newnode(cur, i); G.add_edge(id, trie.trans[cur][i]); dfs(id, next[id][p][i], rest, m, dep + 1, trie.trans[cur][i]); }}bool Graph::match(int x) { for (int i = head[x]; ~i; i = edge[i].next) if (!vis[edge[i].v]) { vis[edge[i].v] = 1; if (!(~link[edge[i].v]) || match(link[edge[i].v])) { link[edge[i].v] = x; pre[x] = edge[i].v; return 1; } } return 0;}//Rhein_E 100pts

转载于:https://www.cnblogs.com/Rhein-E/p/10561531.html

你可能感兴趣的文章
拼图数字游戏
查看>>
PHP 开发 APP 接口 学习笔记与总结 - APP 接口实例 [4] 首页 APP 接口开发方案 ③ 定时读取缓存方式...
查看>>
xml
查看>>
python上下文管理器
查看>>
总结了一些MySQL优化方面的技巧
查看>>
Sql server 将表2中数据更新到表1中
查看>>
ASP.NET_SessionId vs .ASPXAUTH why do we need both of them?
查看>>
Chrome查看JavaScript函数
查看>>
xunit输出output到控制台
查看>>
The OAuth 2.0 Authorization Framework: Bearer Token Usage
查看>>
IIS访问站点,出现connection refused
查看>>
笔记:Android触摸事件传递机制
查看>>
mvc与ssm
查看>>
Java小知识---Java请求一个URL。获取网站返回的数据
查看>>
更改docker服务网段分配地址
查看>>
jquery ajax 回调函数的值alert出来[object Object] 解决方法
查看>>
Redis缓存接入监控、运维平台CacheCloud
查看>>
廖雪峰Java9正则表达式-1正则表达式入门-1正则表达式简介
查看>>
廖雪峰Java11多线程编程-4线程工具类-1ThreadLocal
查看>>
level1 - unit 1 - 句子结构
查看>>