2789: [Poi2012]Letters
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 297 Solved: 197
[ Submit][ Status][ Discuss]
Description
给出两个长度相同且由大写英文字母组成的字符串A、B,保证A和B中每种字母出现的次数相同。
现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B。
Input
第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度。
第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母。
Output
一个非负整数,表示最少的交换次数。
Sample Input
3
ABC
BCA
ABC
BCA
Sample Output
2
HINT
ABC -> BAC -> BCA
Source
题解:权值树状数组求逆序对。
预处理的时候把第一个字符串顺序编号,然后第二个字符串中的字符找到他在第一个串中的位置,并记录。
最后对第二个串记录下来的序列求逆序对。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 1000003
using namespace std;
int n,ch[30][100000],len[N],pd[30];
long long tr[N],ans;
char s[N],s1[N];
int lowbit(int x)
{
return x&(-x);
}
void change(int x,long long v)
{
for (int i=x;i<=n;i+=lowbit(i))
tr[i]+=v;
}
long long sum(int x)
{
int ans=0;
for (int i=x;i;i-=lowbit(i))
ans+=tr[i];
return ans;
}
int main()
{
scanf("%d\n",&n);
scanf("%s",s+1);
scanf("%s",s1+1);
for (int i=1;i<=n;i++)
{
int x=s[i]-'A';
ch[x][++ch[x][0]]=i;
}
for (int i=1;i<=n;i++)
{
int x=s1[i]-'A';
pd[x]++;
len[i]=ch[x][pd[x]];
}
for (int i=n;i>=1;i--)
{
ans+=sum(len[i]);
change(len[i],1);
}
printf("%lld\n",ans);
}