思路:1.首先遍历字符串,记录各个字符的数目b[t];
2.再次遍历字符串,如果当前cnt[t]<b[t]/2,那么我们就可以把他放入前半段字符串中,移动次数为(i-size);否则就将其放入后半段字符串中;
3.最后将后半段字符串根据前半段字符串的顺序得到一个数组,然后通过归并排序来排序,记录的逆序对数;
package Main;
import java.io.*;
import java.util.*;
public class Main1 {
static long ans=0;//最少交换次数
static int b[]=new int[26],cnt[]=new int[26];//b数组用来记录字符串中各字符的数量;cnt数组用来记录在遍历过程中当前各字符是否满足一半的数目
static Vector<Integer> a[]=new Vector[26];//用来记录前半段中字符的下标;
static Vector<Integer> h=new Vector<>(),hh=new Vector<>();//分别记录前后两段字符串
static int aa[];//记录后段字符串对应的下标
public static void main(String[] args) {
int n=cin.nextInt();
String s=cin.nextLine();
char c[]=s.toCharArray();
for(int i=0;i<c.length;i++) {
int t=c[i]-'a';
b[t]++;
}
for(int i=0;i<26;i++)a[i]=new Vector<>();
//将字符串分为前后两段
for(int i=0;i<c.length;i++) {
int t=c[i]-'a';
if(cnt[t]<b[t]/2) {
int size=0;
if(!h.isEmpty())
size=h.size();
cnt[t]++;
ans+=i-size;
h.add(t);
// System.out.println(i+" "+t+" "+size);
a[t].add(h.size());
}else hh.add(t);
}
int id=0;
aa=new int[hh.size()];
//得到后半段字符串的下表
for(int i=0;i<hh.size();i++) {
int t=hh.get(i);
aa[id++]=a[t].get(0);
a[t].remove(0);
}
//归并模板
mergeSort(aa,0,hh.size()-1);
out.println(ans);
out.flush();
}
private static void mergeSort(int[] a, int i, int j) {
// TODO Auto-generated method stub
if(i>=j)return;
int mid=i+(j-i)/2;
mergeSort(a,i,mid);
mergeSort(a,mid+1,j);
merge(a,i,mid,j);
}
private static void merge(int[] a, int left, int mid, int right) {
// TODO Auto-generated method stub
int s1=left;
int s2=mid+1;
int ret[]=new int[right-left+1];
int i=0;
while(s1<=mid&&s2<=right)
{
if(a[s2]<a[s1]) {
ret[i++]=a[s2++];
ans+=mid-s1+1;//求逆序对数目
}
else {
ret[i++]=a[s1++];
}
}
while(s1<=mid)ret[i++]=a[s1++];
while(s2<=right)ret[i++]=a[s2++];
for(int j=0;j<ret.length;j++)
a[j+left]=ret[j];
}
//快输模板
static class FastScanner{
BufferedReader br;
StringTokenizer st;
public FastScanner(InputStream in) {
br=new BufferedReader(new InputStreamReader(in),16384);
eat("");
}
public void eat(String s) {
st=new StringTokenizer(s);
}
public String nextLine() {
try {
return br.readLine();
}catch(IOException e) {
return null;
}
}
public boolean hasNext() {
while(!st.hasMoreTokens()) {
String s=nextLine();
if(s==null)return false;
eat(s);
}
return true;
}
public String next() {
hasNext();
return st.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public double nextDouble() {
return Double.parseDouble(next());
}
}
static FastScanner cin=new FastScanner(System.in);
static FastScanner sc=new FastScanner(System.in);
static PrintWriter out=new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
}