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