题目链接

首先呢,看到 A C G T 对应不同的权值,第一步就是把字母转换成数字。

我们分别对 A->1 C->2 G->3 T->4 进行标号,之后方便 \(\text{dp}\) 。

然后看到题目中对于一个范式的定义:

一个DNA序列属于范式 \(-j(j>1)\) ,只要它属于范式 \(-(j-1)\) 或者是一个范式 \(-(j-1)\) 和一个范式 \(-1\) 的连接。

那我看了半天才看懂是什么意思,简洁来说就是范式为 \(j\) 的串同时也是范式为 \(j+1\) 的串。

其实讲到现在也就是表达一个前缀和的关系。

那我们显然要把前缀和拆开,这样的话更利于我们 \(\text{dp}\) 转移。

用符合题目的思路来说就是:隔断 \(j\) 到 \(j+1\) 这两个范式之间的直升关系。

最后再做一遍前缀和恢复就好了。

考虑怎么 \(\text{dp}\) 。

我们设 \(f_{i,j,k}\) 表示到了第 \(i\) 个位置,当前位是 \(k\) ,且范式为 \(j\) 的方案数。

那么可以得到

\[f_{i,j,k} = \sum_{type = 1}^4f_{i+1,j-[k > type],type}
\]

这个也很好理解吧。

就是说我从后向前转移,枚举后一位的优先级 \(type\) 。

如果当前的优先级 \(k\) 大于后一位的优先级 \(type\) 那么范式一定加一。

这也就是为什么转移方程中会出现 \(j-[k > type]\) 。

转移完成后要记得做一次前缀和。

具体细节可以看代码。

既然 \(f_{i,j,k}\) 都求出来了,那么输出方案也不难了。

对于 \(r\) 比当前方案数多时,那就增加当前的等级,并更新 \(r\) 。

Code

#include <cstdio>
#include <iostream>
#include <algorithm> #define file(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout) #define quad putchar(' ')
#define Enter putchar('\n') #define int long long
const int N = 5e4 + 5; int m, k, r, a[N], f[N][15][5];
char c[N]; inline void print(int num) {
if (num == 1) putchar('A');
if (num == 2) putchar('C');
if (num == 3) putchar('G');
if (num == 4) putchar('T');
} signed main(void) {
// file("P3624");
std::cin >> m >> k >> r;
scanf("%s", c + 1);
for (int i = 1; i <= m; i++) {
if (c[i] == 'A') a[i] = 1;
if (c[i] == 'C') a[i] = 2;
if (c[i] == 'G') a[i] = 3;
if (c[i] == 'T') a[i] = 4;
}
if (a[m] != 0) {
f[m][1][a[m]] = 1;
} else {
for (int i = 1; i <= 4; i++)
f[m][1][i] = 1;
}
for (int i = m - 1; i >= 1; i--) {
if (a[i] != 0) {
for (int j = 1; j <= k; j++) {
for (int l = 1; l <= 4; l++)
f[i][j][a[i]] += f[i + 1][j - (a[i] > l)][l];
}
} else {
for (int num = 1; num <= 4; num ++) {
for (int j = 1; j <= k; j++) {
for (int l = 1; l <= 4; l++)
f[i][j][num] += f[i + 1][j - (num > l)][l];
}
}
}
}
for (int i = 1; i <= m; i++)
for (int j = 1; j <= k; j++)
for (int l = 1; l <= 4; l++)
f[i][j][l] += f[i][j - 1][l];
int last = 0;
for (int i = 1; i <= m; i++) {
if (a[i] != 0) {
print(a[i]);
if (a[i] < last) k --;
last = a[i];
} else {
int chose;
for (chose = 1; chose <= 4 && r > f[i][k - (chose < last)][chose]; chose ++)
r -= f[i][k - (chose < last)][chose];
print(chose);
if (chose < last) k --;
last = chose;
}
}
std::cout << std::endl;
return 0;
}

最新文章

  1. extjs学习之Ext.selection.CheckboxModel
  2. Python 数据处理----对定长数据的处理
  3. docker operation method note
  4. C#WinForm中显示实时时间:年/月/日 时/分/秒 星期X
  5. hdoj 2612 Find a way【bfs+队列】
  6. Unity3D ITween!
  7. Scala AOP
  8. Python中三种基本结构的语句
  9. 怎么调用api接口
  10. 002_JS基础_JavaScript基础语法01
  11. python写zip破解器
  12. 目前微服务/REST的最佳技术栈
  13. 一、学习起步vue——安装
  14. 如何在一台计算机上配置多个jdk【转】
  15. 支持“xxxContext”上下文的模型已在数据库创建后发生更改。请考虑使用 Code First 迁移更新数据库
  16. Eclipse插件安装常见方法
  17. hdu 4864 任务分配贪心
  18. LUA返回的是引用
  19. Linux服务器配置---tftpserver
  20. Android利用广播监听设备网络连接(断网)的变化情况

热门文章

  1. HCNP Routing&amp;Switching之组播技术PIM-SM RP
  2. 手写一个bind
  3. PostgreSQL配置调优在线工具
  4. 5个容易忽视的PostgreSQL查询性能瓶颈
  5. bellman-ford 单源最短路问题 图解
  6. 在windows上安装elasticsearch7.6
  7. 建设Kubernetes生产环境的16条建议
  8. 操作系统实现-boot.asm实现
  9. Linux嵌套目录权限的比较探究
  10. Springcloud及Git线上配置详解