【BZOJ2789】[Poi2012]Letters 树状数组

【BZOJ2789】[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

题解:首先对于B中的第一个字符,我们一定是贪心的选择A中最左边一个与它相同的字符移过来,并且移过来的过程中,其它字符的相对顺序不发生改变。所以我们只需要用树状数组维护每个字符被移动的距离,然后继续做下去即可。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
const int maxn=1000010;
int n;
long long ans;
char A[maxn],B[maxn];
int s[maxn],st[26][maxn],tp[26];
void updata(int x,int v)
{
	for(int i=x;i<=n;i+=i&-i)	s[i]+=v;
}
int query(int x)
{
	int ret=0,i;
	for(i=x;i;i-=i&-i)	ret+=s[i];
	return ret;
}
int main()
{
	scanf("%d%s%s",&n,A+1,B+1);
	int i,u;
	for(i=n;i>=1;i--)	st[A[i]-'A'][++tp[A[i]-'A']]=i;
	for(i=1;i<=n;i++)
	{
		u=st[B[i]-'A'][tp[B[i]-'A']--];
		ans+=query(u)+u-i,updata(1,1),updata(u,-1);
	}
	printf("%lld",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/CQzhangyu/p/7434635.html