隐藏页面特效

[USACO24OPEN] The 'Winning' Gene S 自用存档

1|0[USACO24OPEN] The 'Winning' Gene S


1|1题目背景


注意:本题的内存限制为 512MB,通常限制的 2 倍。

1|2题目描述


在多年举办比赛并看着 Bessie 一次又一次地获得第一名后,Farmer John 意识到这绝非偶然。他得出结论,Bessie 一定将胜利写进了 DNA,于是他开始寻找这种「胜利」基因。

他设计了一个过程来识别这个「胜利」基因的可能候选。他获取了 Bessie 的基因组,为一个长为 N 的字符串 S,其中 1N3000。他选择某个数对 (K,L),其中 1LKN,表示「胜利」基因候选的长度将为 L,并且将在一个较大的 K 长度子串中进行寻找。为了识别这一基因,他从 S 中取出所有 K 长度的子串,我们将称这样的子串为一个 K-mer。对于一个给定的 K-mer,他取出其所有长度为 L 的子串,将字典序最小的子串识别为胜利基因候选(如果存在并列则选择其中最左边的子串),然后将该字串在 S 中的起始位置 pi(从 0 开始索引)写入一个集合 P

由于他还没有选定 KL,他想知道每对 (K,L) 将有多少个候选。

对于 1N 中的每一个 v,帮助他求出满足 |P|=v(K,L) 对的数量。

1|3输入格式


输入的第一行包含 N,为字符串的长度。第二行包含 S,为给定的字符串。输入保证所有字符均为大写字符,其中 siAZ,因为奶牛遗传学远比我们的高级。

1|4输出格式


对于 1N 中的每一个 v,输出满足 |P|=v(K,L) 对的数量,每行输出一个数。

1|5样例 #1


样例输入 #1

8 AGTCAACG

样例输出 #1

11 10 5 4 2 2 1 1

1|6提示


样例解释 1

在这个测试用例中,输出的第三行为 5 是因为我们发现恰好有 5KL 存在三个「胜利」基因候选。这些候选为(其中 pi0 开始索引):

(4,2) -> P = [0,3,4] (5,3) -> P = [0,3,4] (6,4) -> P = [0,3,4] (6,5) -> P = [0,1,3] (6,6) -> P = [0,1,2]

为了了解 (4,2) 如何得到这些结果,我们取出所有的 4-mer

AGTC GTCA TCAA CAAC AACG

对于每一个 4-mer,我们识别出字典序最小的长度为 2 的子串

AGTC -> AG GTCA -> CA TCAA -> AA CAAC -> AA AACG -> AA

我们取出所有这些子串在原字符串中的位置并将它们添加到集合 P 中,得到 P=[0,3,4]

另一方面,如果我们关注 (4,1) 对,我们会发现这只会得到总共 2 个「胜利」基因候选。如果我们取出所有的 4-mer 并识别字典序最小的长度为 1 的子串(用 A,A' 和 A* 来区分不同的 A),我们得到

AGTC -> A GTCA' -> A' TCA'A* -> A' CA'A*C -> A' A'A*CG -> A'

尽管 A' 和 A* 在最后 3 种情况下字典序均为最小,但最左边的子串优先,因此仅有 A' 在所有这些情况中被视为候选。这意味着 P=[0,4]

测试点性质

  • 测试点 24N100
  • 测试点 57N500
  • 测试点 816:没有额外限制。

赛时代码(66)

#include <bits/stdc++.h> using namespace std; const int N = 3005; int n, p[N], cnt[N]; char s[N]; int pl[N][N], qwq[N][N], ll; bool check(int a, int b){ if(pl[a][ll-1] != pl[b][ll-1]) return pl[a][ll-1]<pl[b][ll-1]; if(s[a+ll-1] != s[b+ll-1]) return s[a+ll-1] < s[b+ll-1]; return a < b; } int find(int l, int L, int R){ if(R-L+1 < l) return 0; int minp = L, ret = 1; for(int i = L+1; i+l-1 <= R; i++) if(pl[i][l] < pl[minp][l]) minp = i; ret += find(l, L, minp+l-2); ret += find(l, minp+1, R); cnt[R-L+1]++; return ret; } int main(){ scanf("%d%s", &n, s+1); for(ll = 1; ll <= n; ll++){ for(int i = 1; i+ll-1 <= n; i++) qwq[ll][i] = i; sort(qwq[ll]+1, qwq[ll]+n-ll+2, check); for(int i = 1, cnt = 0; i+ll-1 <= n; i++){ if(pl[qwq[ll][i]][ll-1] != pl[qwq[ll][i-1]][ll-1] || s[qwq[ll][i]+ll-1] != s[qwq[ll][i-1]+ll-1]) cnt++; pl[qwq[ll][i]][ll] = cnt; } } for(int l = 1; l <= n; l++){ find(l, 1, n); for(int i = n; i >= l; i--){ cnt[i] += cnt[i+1]; cnt[i+1] = 0; p[cnt[i]]++; } cnt[l] = 0; } for(int i = 1; i <= n; i++) printf("%d\n", p[i]); return 0; }

__EOF__

本文作者Meteor2008
本文链接https://www.cnblogs.com/meteor2008/p/18160960.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   _kilo-meteor  阅读(82)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示