【题解】P5484 [JLOI2011] 基因补全

我的第一篇题解

题意很明了,求对 T T T 的一种补全方案 (添加字符) 使其与 $ S $ 配对 ( A - T / T - A / C - G / G - C )

首先将 $ $已有的字符逆过来(即变为配对所需的字符),就可以发现 实际是求 S S S 中和 T T T 相同的子串数量

于是这道题就做完了做法很明了…

f i f_i fi 为以 T T T 中第 i i i 个字符结尾的字串数量 (此时字符下标从 1 开始计算)

S S S 从前往后扫一遍,更新数组。

那么具体如何更新呢?

我们知道,当我们在 S S S 的第 i i i 位中扫到 T T T 中的第 j j j 个字符时,它能与所有先前在 S S S 中以 T T T 中第 j − 1 j-1 j1 个字符结尾的子串构成合法子串 ,于是据此得到 DP 方程:

f i = f i + f i − 1 ( S i = T j ) f_i = f_i + f_{i-1} (S_i = T_j) fi=fi+fi1(Si=Tj)

f m f_m fm为最终所求(根据题意, m m m 为字符串 T T T 的长度)。

注意:

  • 运算中数据很大,要开高精度
  • DP 数组要从后往前扫,否则会因为在同一位上不合法的重复更新 (即对 S S S 中同一个字符的反复使用更新 DP 数组) 而 WA (可以类比为 0-1 背包和完全背包之间的区别)。
  • 在处理 T T T 时注意看清代码,不要出现将一个字符变为其对应的字符后又还原的情况(否则会因为变回原字符转换字符无效卡 BUG)。

代码如下:

#include<bits/stdc++.h>
using namespace std;
const int N = 2002;
int n,m,ans[N][N],len[N];
char a[N],b[N];
int main()
{
	cin>>n>>m;
	for(int i = 1;i <= n;i++)
		cin>>a[i];
	for(int i = 1;i <= m;i++)
	{
		cin>>b[i];
		if(b[i] == 'A') b[i] = 'T';
		else if(b[i] == 'T') b[i] = 'A';
		else if(b[i] == 'C') b[i] = 'G';
		else if(b[i] == 'G') b[i] = 'C';
	}
	for(int i = 1;i <= m;i++) len[i] = 1;
	for(int i = 1;i <= n;i++)
		for(int j = m;j >= 1;j--)
		{
			if(a[i] == b[j])
			{
				if(j == 1)
				{
					ans[1][1]++;
					int pos = 1;
					while(ans[1][pos] >= 10)
					{
						ans[1][pos+1]++;
						ans[1][pos] %= 10;
						pos++;
						len[1] = max(len[1],pos);
					}
				}
				else
				{
					int maxlen = max(len[j],len[j-1]);
					for(int k = 1;k <= maxlen;k++)
						ans[j][k] += ans[j-1][k];
					for(int k = 1;k <= maxlen;k++)
						if(ans[j][k] >= 10)
						{
							ans[j][k+1]++;
							ans[j][k] %= 10;
						}
					len[j] = maxlen;
					if(ans[j][maxlen+1]) len[j] = maxlen+1;
				}
			}
		}
	for(int i = len[m];i >= 1;i--)
		cout<<ans[m][i];
	return 0;
}

后记:

Update:

2021.12.17: 更新了 LaTeX 和内容。

2021.12.18: 更新内容。

2021.12.18: 更新LaTeX。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值