bzoj 2789 [Poi2012]Letters 求逆序对

来源:互联网 发布:零基础学c语言txt下载 编辑:程序博客网 时间:2024/06/05 19:48

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 longusing 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;}