我不会火柴排队
交换使得串的前
一样首先得数量一样,我们这里贪心往前面塞,能放则放,容易证明这是正确的。
然后就可以变成两个独立的序列,因为之后在前后之间交换都会是答案不优。
然后我们需要让两个序列的一样,跟火柴排队一样处理就可以了。
但是因为不是排列,对于一样的字母,我们需要让下标小的匹配小的,大的匹配大的,可以用交换证明这样做是正确的,之后对新序列求逆序对就行了。
代码:
#include<bits/stdc++.h>
// #define int long long
#define ll long long
using namespace std;
/*
#pragma region 哈基米
*/
inline int read(){
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
inline string reads(){
string s=" ";char c=getchar();
while(c>'z'||c<'a') c=getchar();
while(c>='a'&&c<='z') {s+=c;c=getchar();}
return s;
}
const int N=2e5+5,S=26;
int n,c[N],p[N],cnt[N];ll ans;vector<int> id[S];int l[S];
struct tree{
int tr[N];
#define lb x&(-x)
void add(int x,int k){while(x<N) tr[x]+=k,x+=lb;}
int sum(int x){int res=0;while(x) res+=tr[x],x-=lb;return res;}
}tr;
signed main(){
// freopen("1.in" ,"r",stdin );
n=read();string s=reads();
for(int i=1;i<=2*n;i++) cnt[p[i]=s[i]-'a']++;
for(int i=0;i<S;i++) cnt[i]/=2;
for(int i=1,k=n+1,j=1;i<=n;i++) {
c[i]=p[j];ans+=j-i;cnt[p[j++]]--;
while(!cnt[p[j]]&&j<=2*n) c[k++]=p[j++];
}
for(int i=1;i<=n;i++) id[c[i]].push_back(i);
for(int i=n+1;i<=2*n;i++) c[i]=id[c[i]][l[c[i]]++];
for(int i=2*n;i>n;i--) {
ans+=tr.sum(c[i]);tr.add(c[i],1);
}
printf("%lld\n",ans);
return 0;
}