#树状数组#洛谷 3531 [POI2012] LIT-Letters
题目
给出两个长度相同且由大写英文字母组成的字符串\(A\)、\(B\),保证\(A\)和\(B\)中每种字母出现的次数相同。
现在每次可以交换\(A\)中相邻两个字符,求最少需要交换多少次可以使得\(A\)变成\(B\)。
分析
举个例子\(dabac\)要变成\(bcada\)
首先,相同字母的先后顺序不会改变,如果改变顺序肯定会使答案不优,那么可以用26个队列装入每个字母在\(A\)串中的顺序,然后用\(B\)串为基准离散化,然后以上面为例就是
队列\(a:2,4;b:3;c:5;d:1\)
然后对应回\(B\)串形成数列\(35214\)
然后可以发现这里面的每个数应该排在相应的位置
那不就是逆序对吗?
树状数组求解!
代码
#include <cstdio>
#include <cctype>
#include <queue>
#define rr register
using namespace std;
const int N=1000011; queue<int>q[27]; int n,b[N],a[N]; long long ans;
inline void add(int x){for (;x<=n;x+=-x&x) ++b[x];}
inline signed query(int x){rr int ans=0; for (;x;x-=-x&x) ans+=b[x]; return ans;}
signed main(){
scanf("%d",&n);
for (rr int i=1;i<=n;++i){
rr char c=getchar();
while (!isalpha(c)) c=getchar();
q[c^64].push(i);
}
for (rr int i=1;i<=n;++i){
rr char c=getchar();
while (!isalpha(c)) c=getchar();
a[i]=q[c^64].front(); q[c^64].pop();
}
for (rr int i=n;i;--i) ans+=query(a[i]-1),add(a[i]);
return !printf("%lld",ans);
}