排序
题目描述
小a有一个DNA序列串,强迫症的小a看它不顺眼,想将它排好序。
给定长为n的DNA序列串s(仅由A,T,G,C最多四种字符构成)。你可以进行任意次如下操作:任选两个位置i,j(i\lt ji<j),交换这两个字符s_i,s_js i,s ,花费为2\times(j-i)-12×(j−i)−1(即:将s_is i
不断与s_{i+1}s i+1 交换,直到移动到j位置,再将s_js j 不断与s_{j-1}s j−1
交换,直到移动到i位置所需的总移动次数)。求将序列串中同种字符划分到一起的最小花费(如字符串AGACG,将其变成AAGGC或GGAAC或CAAGG…都是合法的,最小花费是2:AAGGC)。
输入描述:
输入一行,一个字符串s,表示题目描述所述的DNA序列串。
输出描述:
输出一个整数,表示将s中同种字符划分到一起的最小花费。
这道题的解法比较多,这里介绍一种求逆序对的做法;
分析题目我们会发现,求交换的最小花费就是求这个序列里面的逆序对数量,我们只要枚举24种情况产生的不同序列的最少逆序对数量就行;
代码:
#include<bits/stdc++.h>
#define LL long long
#define pa pair<int,int>
#define lson k<<1
#define rson k<<1|1
#define inf 0x3f3f3f3f
//ios::sync_with_stdio(false);
using namespace std;
const int N=200100;
const int M=200100;
const LL mod=998244353;
int n;
int tr[N];
string s;
int lowbit(int k){
return k&(-k);
}
void add(int p,int q){
while(p<=n){
tr[p]+=q;
p+=lowbit(p);
}
}
LL sum(int p){
LL s=0;
while(p){
s=s+(LL)tr[p];
p-=lowbit(p);
}
return s;
}
int f[N];
char h[4]={'A','T','C','G'};
LL change(int a,int b,int c,int d){
memset(tr,0,sizeof(tr));
for(int i=0;i<n;i++){
if(s[i]==h[a]){
f[i+1]=1;
continue;
}
if(s[i]==h[b]){
f[i+1]=2;
continue;
}
if(s[i]==h[c]){
f[i+1]=3;
continue;
}
if(s[i]==h[d]){
f[i+1]=4;
continue;
}
return 2e17;
}
LL ss=0;
for(int i=1;i<=n;i++){
ss=ss+(LL)i-1LL-sum(f[i]);
add(f[i],1);
}
return ss;
}
int main(){
ios::sync_with_stdio(false);
cin>>s;
n=s.length();
LL mn=2e17;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(i==j) continue;
for(int k=0;k<4;k++){
if(j==k) continue;
for(int l=0;l<4;l++){
if(l==k) continue;
mn=min(mn,change(i,j,k,l));
}
}
}
}
cout<<mn<<endl;
return 0;
}

本文探讨了一种解决DNA序列排序问题的方法,通过计算逆序对数量来确定排序成本。介绍了如何使用Fenwick Tree(Binary Indexed Tree)进行高效计算,以及通过枚举所有可能的字符组合来找到最小花费。
505

被折叠的 条评论
为什么被折叠?



