bzoj 2789 [Poi2012]Letters 求逆序对

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值