Description
给出两个长度相同且由大写英文字母组成的字符串A、B,保证A和B中每种字母出现的次数相同。
现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B。
Input
第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度。
第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母。
Output
一个非负整数,表示最少的交换次数。
Sample Input
3
ABC
BCA
Sample Output
2
HINT
ABC -> BAC -> BCA
传送门
相同的多个字符,肯定都是被交换到离它最近相同字符的位置,
由此构造出一个排列,目标是使得这个排列变成1~n的。
答案就是逆序对数。
具体的证明似乎在火柴排队题解中提过……
那就不多说了。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int
N=1000005;
ll ans;
int n,t1[N],t2[N],c[N],A[N];
queue<int>Q[27];
struct TMP{int x,id;}a[N];
bool cmp(TMP a,TMP b){return a.x<b.x;}
void Merge(int l,int mid,int r){
int l1=0,l2=0;
for (int i=l;i<=mid;i++) t1[++l1]=A[i];
for (int i=mid+1;i<=r;i++) t2[++l2]=A[i];
int i=1,j=1,l3=0;
while (i<=l1 && j<=l2)
if (t1[i]<=t2[j]) c[++l3]=t1[i++];
else ans=ans+(ll)l1-i+1,c[++l3]=t2[j++];
for (;i<=l1;i++) c[++l3]=t1[i];
for (;j<=l2;j++) c[++l3]=t2[j];
for (i=l;i<=r;i++) A[i]=c[i-l+1];
}
void MergeSort(int l,int r){
if (l>=r) return;
int mid=(l+r)>>1;
MergeSort(l,mid);
MergeSort(mid+1,r);
Merge(l,mid,r);
}
int main(){
scanf("%d",&n);
char s1[N],s2[N];
scanf("%s",s1+1),scanf("%s",s2+1);
for(int i=1;i<=n;i++) Q[s1[i]-'A'].push(i);
for(int i=1;i<=n;i++){
A[i]=Q[s2[i]-'A'].front();
Q[s2[i]-'A'].pop();
}
ans=0LL;
MergeSort(1,n);
printf("%lld\n",ans);
return 0;
}