hihoCoder # 1052: Genetic Engineering

Disclaimer: This article is a blogger original article, For reprint please contact the bloggers. https://blog.csdn.net/GregoryHanson/article/details/85274372

topic:

Time limit: 1000ms single point of time: 1000ms Memory Limit: 256MB Description
small and small Hi Ho conducting a genetic engineering experiment. Identical to modify some of their DNA sequences of length N, so that the sequence of the K rearmost DNA bases on top of this base composition K consisting of the sequence.

For example, the sequence "ATCGATAC" and K = 2, the second base may be modified by a "C" so that the top surface of the last two bases of the two bases are "AC". Of course, there are other methods to modify, for example, to the last base of the "T", or directly to the two front and rearmost two bases are modified to "GG".

Hi Ho small and small want to know all the methods, the method requires the least modification bases to modify the number of bases.

Input of the first row contains an integer T (1 <= T <= 10), represents the number of test data.

Each test case comprising two rows, the first row is the length of a "ATCG" 4 uppercase letters is N (1 <= N <= 1000) string. The second row is an integer K (. 1
<= K <= N).

For each set of output data output minimum number of bases to be modified.

Sample input

2
ATCGATAC
2
ATACGTCT 6

Sample Output

1
3

Thinking

I want to start a complex. In fact, this problem can be solved with a very simple form through certain to find the law. Here also introduced a sophisticated approach began to think and simple way.

Recursive (stupid way):

For each string of length N, so that it is equal to substring of characters after the first K K-character string N- (NK) can be reduced to a length so that its front K- (NK) characters substring equal to the issue and after K- (NK) characters of. Wherein, for the n th operation, if n is odd, to take N characters in the previous N- (NK) characters as a substring; if n is an even number, taking the N characters in the N- (NK) characters as substring.
When the recursion up to 2 * K <= N, no string needs to overlap the same parts, without this overlap flag bit string, and to be removed every time assignment of NK characters fallback process recording in which N characters need to be equal. Finally, for all the characters need to be equal position to find out the highest frequency, the total number - that is, when the number of words necessary to change the current highest frequency letters appear. The accumulated number of times all cases, the result obtained.
This method is too complicated, it now appears that time feel stupid , but it was still feel he is very clever. . .

Method to find the law:

Look for the law can be found, This question is required to modify the final result after the fact is a cycle of length substring of NK, as human nature is the same repeater.
From bit 0, the bit order of each NK denoted by the same symbols. For example, suppose N = 10, K = 7, then the position of each marked symbol 0,1,2 1,2,3 3,4,5 position of the symbol labeled 1,2,3, thereby by analogy, the same mark after representatives modify the corresponding character should be the same. After completion mark mark the final step in the implementation of the above recursive method to count the number.

related functions:

Memset (start address, 0, size): starting address value from the spatial size to 0, is used to initialize an array. Headers #include <memory.h>

Ternary operator: equals the same priority, to be added in parentheses in the equation.

possible problems:

1, conventional methods or recursive MLE TLE: not considered a special case of K = N, then enters an infinite loop, the addition of a K = N to Japanese sentence.

2, RE: array size open enough, although the subject can be said that the length of the 1000, but the actual need to open the 2000 looks like the job.

AC Code

Recursion:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#include<memory.h>

using namespace std;
int name[10000];
int num;
string str;

void
digui(int begin, int end, int K, int flag) {
	int shorter = end - begin + 1 - K;
	if ((end - begin + 1) / 2 >= K) {
		int i = 0;
		for (; i < K; i++) {
			name[begin + i] = i + 1;
			name[end - K + 1 + i] = i + 1;
		}
		for (; i <= end - begin - K; i++) {
			name[begin + i] = i + 1;
		}
		num = i;
		return;
	}
	else {
		flag == 1 ? end -= shorter : begin += shorter;
		digui(begin, end, K - shorter, -flag);
		if (flag == 1) {
			for (int i = 0; i < shorter; i++) {
				name[end - i + shorter] = name[end - i];
			}
		}
		else {
			for (int i = 0; i < shorter; i++) {
				name[begin + i - shorter] = name[begin + i];
			}
		}
		return;
	}
}

int main() {
	int T;
	cin >> T;
	while (T--) {
		memset(name, 0, 10000);
		cin >> str;
		int K;
		cin >> K;
		int count = 0;
		if (K == str.size()) {
			cout << 0 << endl;
			continue;
		}
		digui(0, str.size() - 1, K, 1);

		//统计次数
		for (int i = 1; i < num + 1; i++) {
			int a, t, c, g;
			a = t = c = g = 0;
			for (int j = 0; j < str.size(); j++) {
				if (name[j] == i) {
					switch (str[j]) {
					case 'A':a++; break;
					case 'T':t++; break;
					case 'C':c++; break;
					case 'G':g++; break;
					}
				}
			}
			int max1 = c > g ? c : g;
			int max2 = a > t ? a : t;
			count += a + t + c + g - (max1 > max2 ? max1 : max2);
		}
		cout << count << endl;
	}
	return 0;
}

Method to find the law:

#include<iostream>
#include<algorithm>
#include<cmath>
#include<string>
#include<memory.h>

using namespace std;

int main() {
	int T;
	cin >> T;
	while (T--) {
		int name[10000];
		memset(name, 0, 10000);
		int num;
		string str;
		cin >> str;
		int K;
		cin >> K;
		int count = 0;
		if (K == str.size()) {
			cout << 0 << endl;
			continue;
		}
		//哪些位置应该一样
		int begin = 0, end = str.size() - 1;
		int flag = 1;
		int shorter = str.size() - K;
		for (int i = 0; i < str.size(); i++) {
			name[i] = i % shorter + 1;
		}
		num = shorter;
		//统计次数
		for (int i = 1; i < num + 1; i++) {
			int a, t, c, g;
			a = t = c = g = 0;
			for (int j = 0; j < str.size(); j++) {
				if (name[j] == i) {
					switch (str[j]) {
					case 'A':a++; break;
					case 'T':t++; break;
					case 'C':c++; break;
					case 'G':g++; break;
					}
				}
			}
			int max1 = c > g ? c : g;
			int max2 = a > t ? a : t;
			count += a + t + c + g - (max1 > max2 ? max1 : max2);
		}
		cout << count << endl;
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/GregoryHanson/article/details/85274372