老板问了小Q一共 m次,每次给出一个整数
, 要求小Q把这些数每
分为一组,然后把每组进行翻转,小Q想知道每次操作后整个序列中的逆序对个数是多少呢?
例如:
对于序列1 3 4 2,逆序对有(4, 2),(3, 2),总数量为2。
翻转之后为2 4 3 1,逆序对有(2, 1),(4, 3), (4, 1), (3, 1),总数量为4。
第一行一个数
第二行个数,表示初始的序列(
)
第三行一个数
第四行m个数表示
m行每行一个数表示答案。
2 2 1 4 3 4 1 2 0 2
0 6 6 0
初始序列2 1 4 3->
第一次:1 2 3 4 -> 逆序对数为0->
第二次:4 3 2 1 -> 逆序对数为6->
第三次:4 3 2 1 -> 逆序对数为6->
第四次:1 2 3 4 -> 逆序对数为0
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int N = 1 << n;
//正序数组
int[] a = new int[N];
//逆序数组
int[] b = new int[N];
long[] order = new long[n + 1];
long[] reOrder = new long[n + 1];
for (int i = 0; i < N; ++i) {
//正序添加元素
a[i] = sc.nextInt();
//倒序添加元素
b[N - 1 - i] = a[i];
}
int[] tmp = new int[N];
//一次归并求逆序对数
mergeCount(a, 0, N - 1, tmp, reOrder, n);
//一次归并求顺序对数
mergeCount(b, 0, N - 1, tmp, order, n);
int m = sc.nextInt();
while (m-- > 0) {
// 2^i 个元素为一组进行翻转
int q = sc.nextInt();
for (int i = 1; i <= q; ++i) {
long temp = order[i];
order[i] = reOrder[i];
reOrder[i] = temp;
}
long count = 0;
for (int i = 1; i <= n; ++i) {
count += reOrder[i];
}
System.out.println(count);
}
}
private static void mergeCount(int[] nums, int left, int right, int[] temp, long[] reOrder, int index) {
if (left >= right) return;
int mid = (left + right) >>> 1;
mergeCount(nums, left, mid, temp, reOrder, index - 1);
mergeCount(nums, mid + 1, right, temp, reOrder, index - 1);
int i = left, j = mid + 1;
while (i <= mid && j <= right) {
if (nums[i] > nums[j]) {
reOrder[index] += (mid + 1 - i);
++j;
} else {
++i;
}
}
merge(nums, left, mid, right, temp);
}
private static void merge(int[] nums, int left, int mid, int right, int[] temp) {
System.arraycopy(nums, left, temp, left, right - left + 1);
int i = left, j = mid + 1, k = left;
while (i <= mid && j <= right) nums[k++] = temp[i] <= temp[j] ? temp[i++] : temp[j++];
while (i <= mid) nums[k++] = temp[i++];
while (j <= right) nums[k++] = temp[j++];
}
}
import java.util.*;
public class Main{
public static long count = 0;
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] data = new int[(int)Math.pow(2,n)];
for(int i=0; i<(int)Math.pow(2,n); i++){
data[i] = sc.nextInt();
}
int m = sc.nextInt();
int[] q = new int[m];
for(int i=0; i<m; i++){
q[i] = sc.nextInt();
data = reverse(q[i], data);
}
}
public static int[] reverse(int q, int[] data){
int m,n,k;
int[] re = new int[data.length];
int[] re2 = new int[data.length];
k = (int)(Math.pow(2,q));
for(int i=0; i<data.length; i++){
m = i/k;
n = i%k;
re[i] = data[(m+1)*k-n-1];
re2[i] = data[(m+1)*k-n-1];
}
getReverseCount(re2);
System.out.println(count);
count = 0;
return re;
}
//使用归并排序方法计算数组A中的逆序对数
public static void getReverseCount(int[] A) {
if(A.length > 1) {
int[] leftA = getHalfArray(A, 0); //数组A的左半边元素
int[] rightA = getHalfArray(A, 1); //数组A的右半边元素
getReverseCount(leftA);
getReverseCount(rightA);
mergeArray(A, leftA, rightA);
}
}
//根据judge值判断,获取数组A的左半边元素或者右半边元素
public static int[] getHalfArray(int[] A, int judge) {
int[] result;
if(judge == 0) { //返回数组A的左半边
result = new int[A.length / 2];
for(int i = 0;i < A.length / 2;i++)
result[i] = A[i];
} else { //返回数组的右半边
result= new int[A.length - A.length / 2];
for(int i = 0;i < A.length - A.length / 2;i++)
result[i] = A[A.length / 2 + i];
}
return result;
}
//合并数组A的左半边和右半边元素,并按照非降序序列排列
public static void mergeArray(int[] A, int[] leftA, int[] rightA){
int len = 0;
int i = 0;
int j = 0;
int lenL = leftA.length;
int lenR = rightA.length;
while(i < lenL && j < lenR) {
if(leftA[i] > rightA[j]) {
A[len++] = rightA[j++];
count += (lenL - i);
} else {
A[len++] = leftA[i++];
}
}
while(i < lenL)
A[len++] = leftA[i++];
while(j < lenR)
A[len++] = rightA[j++];
}
}