[loj3526]修改DNA

如果$a[x..y]$和$b[x..y]$的某种字符数量不同,显然无解

考虑一个$[x,y]$的排列$p[x..y]$,使得$\forall x\le i\le y,a_{i}=b_{p_{i}}$,即最终要让$i$到$p_{i}$的位置

建有向边$(i,p_{i})$,由于每一个点入度和出度都为1,即构成若干个环,而一个大小为$l$的环仅需要交换$l-1$次即可,那么总交换次数为$(y-x+1)-$环数

问题即构造$p_{i}$并最小化交换次数,也即最大化环数

对于$a_{i}=b_{i}$的位置,令$p_{i}=i$即可,每一个位置都构成一个环

对于$a_{i}\ne b_{i}$的位置,仅关心于$(a_{i},b_{i})$这个二元组的个数,假设有$AT$个$(A,T)$、$AC$个$(A,C)$……

接下来,考虑环的形式,必然是形如$AT$和$TA$的二元组或$AT,CA$和$TC$的三元环

贪心优先选择前者,由于$a[x..y]$和$b[x..y]$的每种字符数量相同,若$AT$比$TA$多,必然$CA$比$AC$多,由此剩下的部分必然构成若干个三元环

(关于贪心的正确性,感性理解即可)

 1 #include<bits/stdc++.h>
 2 #include"dna.h"
 3 using namespace std;
 4 #define N 100005
 5 int n,ans,tot[N][3][3],a[3][3];
 6 int change(char c){
 7     if (c=='A')return 0;
 8     if (c=='T')return 1;
 9     return 2;
10 }
11 void init(string a,string b){
12     n=a.length();
13     for(int i=0;i<n;i++){
14         memcpy(tot[i+1],tot[i],sizeof(tot[i]));
15         tot[i+1][change(a[i])][change(b[i])]++;
16     }
17 }
18 int get_distance(int x,int y){
19     for(int i=0;i<3;i++)
20         for(int j=0;j<3;j++)a[i][j]=tot[y+1][i][j]-tot[x][i][j];
21     for(int i=0;i<3;i++){
22         int s=0;
23         for(int j=0;j<3;j++)s+=a[i][j]-a[j][i];
24         if (s)return -1;
25     }
26     ans=y-x+1;
27     for(int i=0;i<3;i++)ans-=a[i][i];
28     for(int i=0;i<3;i++)
29         for(int j=i+1;j<3;j++)ans-=min(a[i][j],a[j][i]);
30     ans-=abs(a[0][1]-a[1][0]);
31     return ans;
32 }
View Code

 

posted @ 2021-07-12 12:54  PYWBKTDA  阅读(184)  评论(0编辑  收藏  举报