HihoCoder 基因工程
原题链接 http://hihocoder.com/problemset/problem/1052
问题:给定由ATCG组成的长度为N的字符串S,求解最少的改动次数,使得前K个字符序列与后K个字符序列相同,其中 1 <= K <= N
分析:
1)对于长度相同的两个字符串 A 和 B 来说,要将两个字符串变为相同,只需改动所有 Ai 与 Bi 不相同的位置,将 Ai 改成 Bi 或者 Bi 改成 Ai 即可;
2)当 K <= N / 2 时,前K个字符序列 与 后K个字符序列 没有交集,如下图所示,因此按照1)处理即可;
3)当 K > N / 2 时,前K个字符序列 与 后K个字符序列 存在交集,如下图所示,Sn-k...Sk-1 既属于 前K个字符序列 又属于 后K个字符序列:
为了方便描述,取 m = n - k,为满足 前K个字符序列 与 后K个字符序列 相同,S中的元素必须满足如下图所示的相等关系:
这些相等关系约束,相当于将S划分为以下几个字符集合:U0 = {S0, Sm, ..., Sj*m},U1 = {S1, Sm+1, ..., Sj*m+1},...,Ui = {Si, Sm+i ... Sj*m+i},其中 i < m 且 Sj*m+i < N。
针对每一个集合Ui,只需保持出现次数最多的字符不变,将其他字符替换成该字符即可。此时,需修改次数 = 字符总数 - 出现最多的字符数。
显然,2)同样可以采用3)这样的方式处理,只是此时每个集合Ui只包含两个元素。
规则如下:
1)依次遍历每个集合 U0 = {S0, Sm, ..., Sj*m},U1 = {S1, Sm+1, ..., Sj*m+1},...,Ui = {Si, Sm+i ... Sj*m+i},其中 i < min(m, k) 且 Sj*m+i < N
2)针对每个集合Ui,需修改次数 = 字符总数 - 出现最多的字符数
3)累加每个集合Ui的需修改次数即可
代码如下:
1 def solve(): 2 T = int(input()) 3 for i in range(T): 4 S = raw_input() 5 K = int(raw_input()) 6 ret = do_solve(S.strip(" "), K) 7 print(str(ret)) 8 9 10 def do_solve(S, K): 11 ret = 0 12 step = len(S) - K 13 cnt = [0, 0, 0, 0] 14 for i in range(min(K, step)): 15 cnt[0] = cnt[1] = cnt[2] = cnt[3] = 0 16 j = i 17 while j < len(S): 18 if S[j] == 'A': 19 cnt[0] = cnt[0] + 1 20 elif S[j] == 'T': 21 cnt[1] = cnt[1] + 1 22 elif S[j] == 'C': 23 cnt[2] = cnt[2] + 1 24 elif S[j] == 'G': 25 cnt[3] = cnt[3] + 1 26 j += step 27 ret += sum(cnt) - max(cnt) 28 return ret 29 30 31 solve()