题目大意
给出一个字符串(长度<=1000),字符串中的字符均为ATCG中的某一个。给出一个数字K,通过更改字符串中的某些字符,可以使得字符串的前K个字符形成的子串和最后K个字符形成的子串相同,求出最少更改的字符个数。
分析
理解题意,画图之后,仿佛是KMP的结果,但是这和KMP没啥关系...画图分析之后,知道问题应该分情况讨论:记 len 为字符串的长度,result为最少更改的字符个数。
(1) len >= 2*K
两个子串中间没有重合,直接进行比较相应位置上的字符,不同result就加1
(2)len - K > K / 2
两个子串中间有重合,但是分析发现,需要加整个字符串分两个部分进行分别统计。t = 2*K-len. [t, K-t), [K-t, 2*(k-t)) 这两个区域应该相同; 且[0, t), [K-t, K), [len - t, len) 这三个区域相同。
(3)len -K <= K / 2
画图可以知道,此时这个len长度的字符串被分成了连续的长度为(len - K)的一段段的子串,这些子串必须相同,最后一个子串可能长度没有(len - K),它就是前面那些子串的前缀。这样就需要判断,将len长度的字符串分割成连续的长度为(len - K)的子串,需要最少改动多少个字符使得这些子串相同。由于每个位置的字符只能为 ATCG中的一个,因此可以维护数组 gcount[len-K][4],其中 gcount[i][c] 表示 那些子串在各自的i位置上的字符为c(将A映射为0,T为1,C为2,G为3)的个数。遍历完一遍母串之后,求出gcount数组,对于每个位置i,都可以求出gcount[i]中的和 sum,以及最大值 max,sum-max即为需要发生的变动,将所有的位置处需要发生的变动加和。
实现
#pragma once #pragma execution_character_set("utf-8") // 本文件为utf-8 编码格式 #include<iostream> #include<stdio.h> #include<string.h> using namespace std; char gene[1005]; int gcount[1005][4]; int main(){ int T, k; scanf("%d", &T); while (T--){ getchar(); scanf("%s", gene); scanf("%d", &k); int len = strlen(gene); int result = 0; if (len <= k){ result = 0; } else if (len >= 2 * k){ for (int i = 0; i < k; i++){ if (gene[i] != gene[i + len - k]) result++; } } else if(len - k > k / 2){ int t = 2 * k - len; for (int i = t; i < k - t; i++){ if (gene[i] != gene[i + k - t]) result++; } for (int i = 0; i < t; i++){ char a = gene[i]; char b = gene[i + k - t]; char c = gene[i + len - t]; if (a == b){ if (a != c) result++; } else if (a == c){ if (a != b) result++; } else if (b == c){ if (b != a) result++; } else result += 2; } } else{ memset(gcount, 0, sizeof(gcount)); for (int i = 0; i < len; i++){ int index = i % (len - k); if (gene[i] == 'A') gcount[index][0]++; else if (gene[i] == 'T') gcount[index][1] ++; else if (gene[i] == 'C') gcount[index][2] ++; else if (gene[i] == 'G') gcount[index][3] ++; } for (int index = 0; index < (len - k); index++){ int sum = 0, max = 0; for (int i = 0; i < 4; i++){ sum += gcount[index][i]; max = max > gcount[index][i] ? max : gcount[index][i]; } result += (sum - max); } } printf("%d ", result); } return 0; }