【UOJ 494】DNA序列(贪心)(Lyndon分解)

DNA序列

题目链接:UOJ 494

题目大意

给你 n 个字符串,要你每个都选一段非空前缀按某种顺序拼在一起使得形成的大字符串字典序最小。

思路

假设如果知道插入的顺序,我们要怎么选前缀。
发现如果前面的 n1 个都安排好了,那你最后一个选啥是确定的(只选一个字符)
那倒数第一个就确定了,接着看第 n1 个那你就枚举所有的前缀跟最后一个加一下,选最小的方案。(选最小的准没错,因为不会再后面变劣)
那这样倒着贪心就能构造出字符串。

于是考虑顺序。
那你会发现直观的看我们肯定是先放第一个是 A,接着是 C,G,T 这样的。
然后如果那个数的接下来一个小于它,那其实我们应该吧它选上。
然后思考会发现其实它是最大表示串,其实就是 > 为比较的 Lyndon Word。
(因为后缀都比它大那我们把所有前缀循环展开也是前面比它大了)
那我们可以用 Lyndon 分解找到第一个串。

那你可以按这个排序来确定顺序,但是要注意的是这里的也是循环展开比较。
那因为必定不是循环串,我们可以在后面加一个很大的字符,加速上面的操作。

但是还有问题,就是这个 Lyndon Word 可能会一样。
那你考虑一样的内部如何安排顺序,那最后一个的后面可能会放一些东西。
那放啥呢?设 Lyndon Word 是 s,那你串可以表示成 sk+s 的一段前缀,那你就是要让 s 字典序最小(记得也要展开,即加大字符)
那你就直接按 s 从大到小排序即可。

代码

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int N = 55; struct node { string fir, tail, all; }a[N]; int n; char tmp[N]; int getr(int n, int l) { int x = l; for (int now = l + 1; now <= n; now++) { if (tmp[now] > tmp[x]) return now - x; if (tmp[x] == tmp[now]) x++; else x = 0; } return n; } bool same(int l1, int l2, int sz) { for (int i = 1; i <= sz; i++) if (tmp[l1 + i - 1] != tmp[l2 + i - 1]) return 0; return 1; } bool cmp(node x, node y) { if (x.fir != y.fir) return x.fir < y.fir; return x.tail > y.tail; } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%s", tmp); int m = strlen(tmp); tmp[m] = 'Z'; int d = getr(m, 0), now = d; while (same(0, now, d)) now += d; a[i].fir.clear(); a[i].tail.clear(); a[i].fir = string(tmp, tmp + d) + 'Z'; a[i].tail = string(tmp + now, tmp + m + 1) + 'Z'; a[i].all = string(tmp, tmp + m + 1); // cout << a[i].fir << endl << a[i].tail << endl; } sort(a + 1, a + n + 1, cmp); string ans; for (int i = n; i >= 1; i--) { string now = a[i].all[0] + ans; string tmp; tmp = tmp + a[i].all[0]; for (int j = 1; j < a[i].all.size(); j++) { tmp = tmp + a[i].all[j]; now = min(now, tmp + ans); } ans = now; // cout << ans << endl; } cout << ans; return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/LOJ_494.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(69)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2021-11-10 【luogu P6800】Chirp Z-Transform(多项式)(NTT)(bluestein 算法)
点击右上角即可分享
微信分享提示