【bzoj2789】[Poi2012]Letters 树状数组求逆序对
题目描述
给出两个长度相同且由大写英文字母组成的字符串A、B,保证A和B中每种字母出现的次数相同。
现在每次可以交换A中相邻两个字符,求最少需要交换多少次可以使得A变成B。
输入
第一行一个正整数n (2<=n<=1,000,000),表示字符串的长度。
第二行和第三行各一个长度为n的字符串,并且只包含大写英文字母。
输出
一个非负整数,表示最少的交换次数。
样例输入
3
ABC
BCA
样例输出
2
题解
树状数组求逆序对
一个结论:将序列A通过交换相邻元素变换为序列B,需要的最小次数为A中元素在B中的位置所组成的序列的逆序对数。
当出现重复元素时,由于互不影响,所以让它们按照递增的顺序出现,不产生逆序对就好了。
然后用树状数组统计一下逆序对数即可。
#include <cstdio> #include <cstring> #include <algorithm> #define N 1000010 using namespace std; char A[N] , B[N]; int n , head[26] , next[N] , f[N]; void add(int x) { int i; for(i = x ; i <= n ; i += i & -i) f[i] ++ ; } int query(int x) { int i , ans = 0; for(i = x ; i ; i -= i & -i) ans += f[i]; return ans; } int main() { int i , t; long long ans = 0; scanf("%d%s%s" , &n , A + 1 , B + 1); for(i = 1 ; i <= n ; i ++ ) next[i] = head[A[i] - 'A'] , head[A[i] - 'A'] = i; for(i = n ; i >= 1 ; i -- ) t = head[B[i] - 'A'] , head[B[i] - 'A'] = next[t] , ans += query(t) , add(t); printf("%lld\n" , ans); return 0; }