时间限制:1000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi和小Ho正在进行一项基因工程实验。他们要修改一段长度为N的DNA序列,使得这段DNA上最前面的K个碱基组成的序列与最后面的K个碱基组成的序列完全一致。
例如对于序列"ATCGATAC"和K=2,可以通过将第二个碱基修改为"C"使得最前面2个碱基与最后面两个碱基都为"AC"。当然还存在其他修改方法,例如将最后一个碱基改为"T",或者直接将最前面两个和最后面两个碱基都修改为"GG"。
小Hi和小Ho希望知道在所有方法中,修改碱基最少的方法需要修改多少个碱基。
输入
第一行包含一个整数T(1 <= T <= 10),代表测试数据的数量。
每组测试数据包含2行,第一行是一个由"ATCG"4个大写字母组成的长度为N(1 <= N <= 1000)的字符串。第二行是一个整数K(1 <= K <= N)。
输出
对于每组数据输出最少需要修改的碱基数量。
样例输入
2 ATCGATAC 2 ATACGTCT 6
样例输出
扫描二维码关注公众号,回复:
3736544 查看本文章
1 3
题解:如果字符串长度 len >= 2*k ,直接比较就行,否则,规律是 统计下标 i 与 n-k 的余数总数 - 出现频率次数最多的次数
注意:如果 n-k 为0的话,直接输出0
#include<stdio.h>
#include<queue>
#include<string.h>
#include<algorithm>
#include<set>
#include<map>
#include<math.h>
#include<stack>
#include<vector>
#include<bitset>
#include<iostream>
#define ullmax 1844674407370955161
#define llmax 9223372036854775807
#define intmax 2147483647
#define re register
#define pushup() tree[rt]=max(tree[rt<<1],tree[rt<<1|1])
using namespace std;
char s[1500];
struct fun{
int a[30]; // 统计字母出现次数
int num,maxx; // num 指总次数, maxx 字母出现的最大次数
}f[1001];
int main(){
int t,k;
scanf("%d",&t);
while(t--){
scanf(" %s",s);
scanf("%d",&k);
int len=strlen(s);
int ans=0;
if(len>=2*k){
for(int i=0,j=len-k;i<k&&j<len;i++,j++)
if(s[i]!=s[j]) ans++;
printf("%d\n",ans);
}
else{
for(int i=0;i<1001;i++){
memset(f[i].a,0,sizeof(f[i].a));
f[i].num=0; f[i].maxx=0;
}
int m=len-k;
if(m==0){ // 注意 m 为 0 的情况
printf("0\n");
continue;
}
for(int i=0;i<len;i++){
f[i%m].a[s[i]-'A']++;
f[i%m].num++;
}
int ans=0;
for(int i=0;i<m;i++){
int sum=0;
for(int j=0;j<28;j++){
sum=max(sum,f[i].a[j]);
}
f[i].maxx=sum;
ans+=f[i].num-f[i].maxx;
}
printf("%d\n",ans);
}
}
return 0;
}