[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$多,由此剩下的部分必然构成若干个三元环
(关于贪心的正确性,感性理解即可)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }