[ POI 2012 ] Letters
\(\\\)
\(Description\)
给出两个长度为 \(N\) 的字符串\(S_1,S_2\),且保证两个字符串中每一个字符出现次数相同。
现在一次操作可以交换相邻的两个字符,问将 \(S_2\) 变成 \(S_1\) 最少需要交换多少次。
- \(N\le 10^6\)
\(\\\)
\(Solution\)
假如一共出现了五个 \(A\) ,那一定是按照顺序移动,即\(S_2\)中第一个出现的 \(A\) 最后一定会移动到\(S_1\)中第一个出现的 \(A\) 处。
然后就是逐一匹配的问题了。
以第一个串每一个字符的位置做为权值绑在第二个串对应字符的位置上,相当于将第一个串的 \(id\) 按照第二个串的位置打乱再冒泡排序。
然后根据冒泡排序的原理,这个序列的逆序对数就是交换次数。
\(\\\)
\(Code\)
#include<cmath>
#include<vector>
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1000010
#define R register
#define gc getchar
using namespace std;
typedef long long ll;
inline ll rd(){
ll x=0; bool f=0; char c=gc();
while(!isdigit(c)){if(c=='-')f=1;c=gc();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
return f?-x:x;
}
ll n,ans,s[N],ptr[30];
vector<int> p[30];
struct BIT{
ll c[N];
inline int lowbit(ll x){return x&-x;}
inline void add(ll p,ll x){for(;p<=N;p+=lowbit(p)) c[p]+=x;}
inline ll query(ll p){
ll res=0;
for(;p;p-=lowbit(p)) res+=c[p];
return res;
}
}bit;
int main(){
n=rd();
char c=gc();
for(R int i=1;i<=n;++i){
while(!isalpha(c)) c=gc();
p[c-'A'+1].push_back(i); c=gc();
}
for(R int i=1;i<=n;++i){
while(!isalpha(c)) c=gc();
s[i]=p[c-'A'+1][ptr[c-'A'+1]];
++ptr[c-'A'+1]; c=gc();
}
for(R int i=n;i;--i){
ans+=bit.query(s[i]);
bit.add(s[i],1);
}
printf("%lld\n",ans);
return 0;
}