第一行一个数
第二行个数,表示初始的序列(
)
第三行一个数
第四行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++];
}
}
#include<stdio.h>
#include<vector>
using namespace std;
long long n, m, total, sum, offset, num;
vector<long long> count;
vector<long long> l;
vector<long long> l_copy;
vector<long long> max_c;
void mergesort(long long index, long long size)
{
if(size == 0)
{
l_copy[index] = l[index];
return;
}
vector<long long> l_copy2(1<<size);
long long st1 = index, st2 = index + (1 << (size - 1) ), ed1 = st2, ed2 = index + (1 << size);
long long pos = 0, p1 = st1, p2 = st2;
mergesort(st1, size - 1);
mergesort(st2, size - 1);
while(p1 < ed1 && p2 < ed2)
{
if(l_copy[p1] == l_copy[p2]){
long long c1 = 1, c2 = 1;
l_copy2[pos++] = l_copy[p1++];
l_copy2[pos++] = l_copy[p2++];
while(p1 < ed1 && l_copy[p1] == l_copy[p1 - 1]) l_copy2[pos++] = l_copy[p1++], ++c1;
while(p2 < ed2 && l_copy[p2] == l_copy[p2 - 1]) l_copy2[pos++] = l_copy[p2++], ++c2;
max_c[size] -= c1 * c2;
count[size] += (ed1 - p1) * c2;
}
else if(l_copy[p1] < l_copy[p2]){
l_copy2[pos++] = l_copy[p1++];
}
else {
count[size] += ed1 - p1;
l_copy2[pos++] = l_copy[p2++];
}
}
if(p1 == ed1)while(p2 != ed2) l_copy2[pos++] = l_copy[p2++];
else if(p2 == ed2) while(p1 != ed1) l_copy2[pos++] = l_copy[p1++];
for(long long i = st1; i < ed2; ++i) l_copy[i] = l_copy2[i - st1];
}
int main()
{
scanf("%lld", &n);
total = (long long)1 << n;
count.resize(n + 1);
max_c.resize(n + 1);
l.resize(total);
l_copy.resize(total);
for(long long i = 0; i < total; ++i) scanf("%lld", &l[i]);
max_c[0] = 1;
for(long long i = 1; i <= n; ++i) max_c[i] = (long long)1 <<(n + i - 2);//(1 << 2 * (i - 1) ) * ( 1 << (n - i))
mergesort(0, n);
scanf("%lld", &m);
for(long long i = 0; i < m; ++i)
{
scanf("%lld", &num);
sum = 0;
for(long long j = 1; j <= n; ++j)
{
if(j <= num) count[j] = max_c[j] - count[j];
sum += count[j];
}
printf("%lld\n", sum);
}
} 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];
//a 的逆序数组,比如 a = [4,3,2,1], b = [1,2,3,4]
int[] b = new int[N];
/*
order[i] 表示 2^i 的 顺序对个数
reOrder[i] 表示 2^i 的 逆序对个数
比如 i = 1,那么就是每 2 个元素的逆序对的个数,比如 [4,3,2,1],
有 [2,1] [4,3] 两个逆序对,即 reOrder[1] = 2
比如 i = 2,那么就是每 4 个元素的逆序对的个数,比如 [4,3,2,1],
有 [4,3] [2,1] [4,2] [4,1] [3,2] [3,1] 6 个逆序对,
只不过 [2,1] [4,3] 在 i = 1 的时候算过了,因此有 4 个
即 reOrder[2] = 4
我们可以发现,如果大小为 n 的数组是降序的,
那么逆序对个数为 n * (n - 1) / 2 个
比如 [4,3,2,1]
对于 4 来说,后面有 [3,2,1] 3 个元素小于它,那么逆序对个数为 3
对于 3 来说,逆序对个数为 2
对于 2 来说逆序对个数为 1
如果数组是降序的,那么逆序对个数为
(n - 1) + (n - 2) + ... + 1
= n * (n - 1) / 2
而顺序对的个数为 0,但如果我们将其中两个元素交换位置,
减少了 m 个逆序对的同时就会增加 m 个顺序对
这表示 顺序对的个数 + 逆序对的个数 = n * (n - 1) / 2,
即 顺序对 和 逆序对 是互补的
或者这么说,当数组的逆序对个数为 m, 顺序对的个数为 n
那么数组翻转过后,逆序对和顺序对的个数相互交换
即逆序对的个数变为 n, 顺序对的个数变为 m
因此,当我们对 2^i 个元素进行翻转的时候
实际上就是交换它们的顺序对和逆序对个数
*/
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];
}
//一次归并求逆序对数
mergeSort(a, 0, N - 1, reOrder, n);
//一次归并求顺序对数
mergeSort(b, 0, N - 1, 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 mergeSort(int[] arr, int left, int right, long[] reOrder, int index){
if(left < right){
int mid = (left + right) >>> 1;
//归并使得 左右两边保证有序
mergeSort(arr, left, mid, reOrder, index - 1);
mergeSort(arr, mid + 1, right, reOrder, index - 1);
if(arr[mid] > arr[mid + 1]){
mertSort(arr, left, right, mid, reOrder, index);
}
}
}
public static void mertSort(int[] arr, int left, int right, int mid, long[] reOrder, int index) {
//mid 属于左边
int len1 = mid - left + 1;
int len2 = right - mid;
int[] l = new int[len1];
int[] r = new int[len2];
System.arraycopy(arr, left, l, 0, len1);
System.arraycopy(arr, mid + 1, r, 0, len2);
/*
逆序对:l[i] > r[j]
[left, mid) 是有序的,[mid, right] 是有序的
因此,如果 l[i] > r[j],表示 l[i] 比 [0, j] 这些元素都大
那么逆序对个数对于 l[i] 来说,有 j + 1个
*/
int i = len1 - 1;
int j = len2 - 1;
int k = right;
long c = 0;
while(i >= 0 && j >= 0){
if(l[i] > r[j]){
c += j + 1;
arr[k] = l[i];
i--;
}else{
arr[k] = r[j];
j--;
}
k--;
}
System.arraycopy(r, 0, arr, left, j + 1);
//逆序对个数
reOrder[index] += c;
}
} #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(1<<20)+50;;
int n,m,q[maxn],a[maxn],v1[maxn],v2[maxn];
ll rev[50],nor[50];
void init(int o,int l,int r,ll rev[],int nums[]){
if(r==l){
return;
}
int mid=(l+r)/2;
init(o-1,l,mid,rev,nums);
init(o-1,mid+1,r,rev,nums);
ll no=0,re=0;
int i=l,j=mid+1,k=l;
for (i=l,j=mid+1,k=l;i<=mid && j<=r;){
if(nums[i]<=nums[j]){
a[k++]=nums[i];
i++;
}
else{
a[k++]=nums[j];
re+=1L*mid+1-i;
j++;
}
}
if(i<=mid){
while (i<=mid){
a[k++]=nums[i++];
}
}
if(j<=r){
while (j<=r){
a[k++]=nums[j++];
}
}
rev[o]+=re;
for (i=l;i<=r;i++){
nums[i]=a[i];
}
}
ll solve(int o){
for (int i=o;i>=0;i--){
swap(nor[i],rev[i]);
}
ll ans=0;
for (int i=0;i<=n;i++){
ans+=rev[i];
}
return ans;
}
int main(){
cin>>n;
int temp;
//vector<int> v1,v2;
for (int i=0;i<(1<<n);i++){
scanf("%d",&temp);
v1[i]=temp;
v2[i]=temp;
}
cin>>m;
for (int i=0;i<m;i++){
scanf("%d",&q[i]);
}
memset(nor,0,sizeof(nor));
memset(rev,0,sizeof(rev));
init(n,0,(1<<n)-1,rev,v1);
reverse(v2,v2+(1<<n));
init(n,0,(1<<n)-1,nor,v2);
for (int i=0;i<m;i++){
cout<<solve(q[i])<<endl;
}
} 求逆序对问题用归并排序的时间复杂度比暴力算法更低。
假设有一个数组{8,1,2,5,7,4,3,6}
首先归并排序第一次对数组进行分割 8 1 2 5 7 4 3 6
二次分割 8 1 25 74 36
三次分割 8 1 2 5 7 4 3 6
第一次合并 18 25 47 36 reorder[1]=2, order[1]=2
//用reorder[i]来记录第i次合并中存在的逆序对数,order[i]来记录第i次合并中存在的顺序对数。
第二次合并 1258 3467 reorder[2]=5, order[2]=3
第三次合并 12345678 reorder[3]=6, order[3]=10
那么数组{8,1,2,5,7,4,3,6}中存在的逆序对就等于reorder[1]+reorder[2]+reorder[3]=13
将数组{8,1,2,5,7,4,3,6}每2^2个为一组进行翻转{5,2,1,8,6,3,4,7}
首先归并排序第一次对数组进行分割 5 2 1 8 6 3 4 7
二次分割 5 2 18 63 47
三次分割 5 2 1 8 6 3 4 7
第一次合并 25 18 36 47 reorder[1]=2, order[1]=2
第二次合并 1258 3467 reorder[2]=3, order[2]=5
第三次合并 12345678 reorder[3]=6, order[3]=10
那么数组{5,2,1,8,6,3,4,7}中存在的逆序对就等于reorder[1]+reorder[2]+reorder[3]=11
由此我们可以观察到对数组每2^2个进行翻转时,reorder[1]和order[1]进行了互换,reorder[2]和order[2]亦是如此。
所以对数组每2^i个进行翻转时,我们可以把1~i的reorder和order数组元素互换即可继续通过计算reorder数组的累加和来求得数组的逆序对数。
import java.util.ArrayList;
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];//用来存储数组的逆序,对逆序的数组进行一次归并排序可以直接得到order数组
int[] order = new int[n + 1];//为了便于计算,所以设置order下标是1~n,因此数组大小为n+1
int[] reorder = new int[n + 1];
for (int i = 0; i < N; i++)
{
a[i] = sc.nextInt();
b[N - i - 1] = a[i];
}
MergeSort(a, 0, N - 1, reorder, n);//对整个数组进行归并排序,n表示对reorder[1]~reorder[n]进行初始化
MergeSort(b, 0, N - 1, order, n);//对整个逆序数组进行归并排序,完成对order[1]~order[n]的初始化
int m = sc.nextInt();
while(m-- > 0)
{
int count = 0;
int q = sc.nextInt();
for (int i = 1; i <= q; i++) //像之前讲的,将1~q的reorder[i]和order[i]进行互换
{
int temp = reorder[i];
reorder[i] = order[i];
order[i] = temp;
}
for (int i = 1; i <= n; i++)
{
count+= reorder[i];//累加reorder数组,求得对数组中每2^q个元素进行翻转后的逆序对数
}
System.out.println(count);
}
}
public static void MergeSort(int[] a , int left, int right, int[] reorder, int index)
{
if(left < right)
{
int mid = (right + left) / 2;
MergeSort(a, left, mid, reorder,index - 1);
MergeSort(a, mid + 1, right, reorder,index -1);
if(a[mid] > a[mid+1])//如果a[mid]<=a[mid+1],则原数组有序,不需要合并
Merge(a, left, right,reorder, index);
}
}
public static void Merge(int[] a, int left, int right,int[] reorder, int index)//index表示对reorder[index]进行初始化
{
int mid = (right + left) / 2;
int Length1 = mid - left + 1;
int Length2 = right - mid;
int[] l = new int[Length1];//存储a[left]~a[mid]
int[] r = new int[Length2];//存储a[mid+1]~a[right]
System.arraycopy(a, left, l, 0, Length1);//对l进行初始化
System.arraycopy(a, mid + 1, r, 0, Length2);//对r进行初始化
int i = 0;
int j = 0;
int c= 0;
int k = left;
while(i < Length1 && j < Length2)
{
if(l[i] <= r[j])
{
a[k] = l[i];
i++;
}
else
{
a[k] = r[j];
j++;
c += Length1 - i;//当l[i]>r[j]时,因为l是递增序列,所以l[i]~l[Length1-1]均>r[j],所以有Length1-i个元素大于r[j]
}
k++;
}
System.arraycopy(l, i, a, k, Length1 - i);//前面归并排序MergeSort中调用Merge合并的条件是a[mid]>a[mid+1],因为当a[mid]<=a[mid+1]时说明原数组有序,无需合并。l[Length1-1]>r[Length2-1],即l数组的最大值大于r数组的最大值,所以当r中的数全部进入a数组后,l数组中仍有剩余。
reorder[index] += c;
}
import java.util.*;
public class Main {
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = 1<<n;
int[] a = new int[k];
int[] b = new int[k];
for(int i=0;i<k;i++){
a[i] = sc.nextInt();
b[k-1-i] = a[i];
}
int m = sc.nextInt();
int[] q = new int[m];
for(int i=0;i<m;i++){
q[i] = sc.nextInt();
}
getAns(n,a,b,m,q);
}
public static void getAns(int n,int[] a,int[] b,int m,int[] q){
int k = a.length;
int[] tmp = new int[k];
long[] reorder = new long[n+1];
long[] order = new long[n+1];
reverse(a,0,k-1,reorder,tmp,n);
reverse(b,0,k-1,order,tmp,n);
for(int i=0;i<m;i++){
int cur = q[i];
for(int j=1;j<=cur;j++){
long temp = reorder[j];
reorder[j] = order[j];
order[j] = temp;
}
long count = 0;
for(int j=1;j<=n;j++){
count+=reorder[j];
}
System.out.println(count);
}
}
public static void reverse(int[] arr,int left,int right,long[] reorder,int[] tmp,int index){
if(left<right){
int mid = (left+right)>>>1;
reverse(arr,left,mid,reorder,tmp,index-1);
reverse(arr,mid+1,right,reorder,tmp,index-1);
if(arr[mid]>arr[mid+1])
reverseCross(arr,left,mid,right,reorder,tmp,index);
}
}
public static void reverseCross(int[] arr,int left,int mid,int right,long[] reorder,int[] tmp,int index){
for(int i=left;i<=right;i++){
tmp[i] = arr[i];
}
int i = left,j = mid+1;
long count = 0;
for(int k=left;k<=right;k++){
if(i==mid+1){
arr[k] = tmp[j];
j++;
}else if(j==right+1){
arr[k] = tmp[i];
i++;
}else if(tmp[i]<=tmp[j]){
arr[k] = tmp[i];
i++;
}else if(tmp[i]>tmp[j]){
arr[k] = tmp[j];
j++;
count+=mid-i+1;
}
}
reorder[index] += count;
}
} #include <iostream>
#include <random>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
using ll=long long;
int main() {
int n; cin>>n;
vector<ll>a((1<<n)+1);
for(int i=1;i<=1<<n;i++)cin>>a[i];
vector<ll>f(n+1),g(n+1),c((1<<n)+1),b(a);
auto divide=[&](auto divide,int l,int r,int dep)->void{
if(l==r)return;
int mid=l+r>>1;
divide(divide,l,mid,dep-1);
divide(divide,mid+1,r,dep-1);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(a[i]<=a[j])c[k++]=a[i++];
else c[k++]=a[j++],f[dep]+=mid-i+1;
}
while(i<=mid)c[k++]=a[i++];
while(j<=r)c[k++]=a[j++];
for(int k=l;k<=r;k++)a[k]=c[k];
};
divide(divide,1,1<<n,n);
a=b;
auto divide1=[&](auto divide1,int l,int r,int dep)->void{
if(l==r)return;
int mid=l+r>>1;
divide1(divide1,l,mid,dep-1);
divide1(divide1,mid+1,r,dep-1);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(a[i]<a[j])c[k++]=a[i++],g[dep]+=r-j+1;
else c[k++]=a[j++];
}
while(i<=mid)c[k++]=a[i++];
while(j<=r)c[k++]=a[j++];
for(int k=l;k<=r;k++)a[k]=c[k];
};
divide1(divide1,1,1<<n,n);
vector<int>d(n+1);
int m; cin>>m;
while(m--)
{
int q; cin>>q;
ll ans=0;
for(int i=n;i>=1;i--)
{
if(i<=q)d[i]^=1;
if(d[i])ans+=g[i];
else ans+=f[i];
}
cout<<ans<<"\n";
}
return 0;
} #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
vector<int> tmp;
vector<pair<ll,ll>> res;
void merge(vector<int>& data, int l, int r)
{
if (l == r) return;
int mid = (l + r) >> 1;
merge(data, l, mid);
merge(data, mid + 1, r);
int i = l, j = mid + 1, pos = l;
int step = r - l + 1, exp = 0;
while ((1 << exp) != step) ++exp;
while (i <= mid && j <= r)
{
if (tmp[i] > tmp[j])
{
data[pos++] = tmp[i++];
res[exp].first += r - j + 1;
}
else if (tmp[i] < tmp[j])
{
data[pos++] = tmp[j++];
res[exp].second += mid - i + 1;
}
else
{
int val = tmp[i];
int ii = i, jj = j;
while (ii <= mid)
{
if (tmp[ii] == val) data[pos++] = tmp[ii++];
else break;
}
while (jj <= r)
{
if (tmp[jj] == val) data[pos++] = tmp[jj++];
else break;
}
res[exp].first += (r - jj + 1)*(ii - i);
res[exp].second += (mid - ii + 1)*(jj - j);
i = ii, j = jj;
}
}
while (i <= mid)
data[pos++] = tmp[i++];
while (j <= r)
data[pos++] = tmp[j++];
while (l <= r)
{
tmp[l] = data[l];
++l;
}
}
int main()
{
int n, m;
cin >> n;
long long num = pow(2, n);
vector<int> numList(num);
for (int i = 0; i < num; ++i)
cin >> numList[i];
tmp = numList;
res.resize(n + 1, { 0,0 });
merge(numList, 0, num - 1);
cin >> m;
int q;
for (int i = 0; i < m; ++i)
{
cin >> q;
ll ret = 0;
for (int j = 1; j <= q; ++j)
{
swap(res[j].first, res[j].second);
ret += res[j].first;
}
for (int j = q + 1; j <= n; ++j)
ret += res[j].first;
cout << ret << endl;
}
return 0;
}
//为什么我只能过60% 我写的有什么问题?
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
using gg=long long;
void sort(vector<gg>&a,vector<gg>&tmp,vector<gg>&reord,vector<gg>&ord,gg l,gg r,gg id)
{
if(r==l){
return;
}
gg mid=l+((r-l)>>1);
sort(a,tmp,reord,ord,l,mid,id-1);
sort(a,tmp,reord,ord,mid+1,r,id-1);
gg i=l,j=mid+1,k=0;
while(i<=mid && j<=r)
{
if(a[i]>a[j])
{
reord[id]+=mid-i+1;
tmp[k++]=a[j++];
}else {
ord[id]+=r-j+1;
tmp[k++]=a[i++];
}
}
while(i<=mid)
{
tmp[k++]=a[i++];
}
while(j<=r)
{
tmp[k++]=a[j++];
}
for(gg i=l,k=0;i<=r;i++)
{
a[i]=tmp[k++];
}
}
int main() {
gg N;
cin>>N;
gg n=1<<N;
vector<gg>a(n);
for(gg i=0;i<n;i++)
{
cin>>a[i];
}
vector<gg>tmp(n,0);
vector<gg>reord(N+1,0);
vector<gg>ord(N+1,0);
sort(a,tmp,reord,ord,0,n-1,N);
gg m;
cin>>m;
while(m--)
{
gg q;
cin>>q;
gg res=0;
//第q层~1层交换reord~ord;
for(gg i=q;i>=1;i--)
swap(ord[i],reord[i]);
for(gg i=1;i<=N;i++)
res+=reord[i];
cout<<res<<'\n';
}
return 0;
}
// 64 位输出请用 printf("%lld")
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN=(1<<20)+5;
ll n,nn,m,a[MAXN],b[MAXN],f[25],z[25],c[MAXN];
void msort(ll a[],ll l,ll r,ll d,ll g[])
{
if(l>=r)
return ;
int mid=l+r>>1;
msort(a,l,mid,d-1,g);
msort(a,mid+1,r,d-1,g);
ll i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(a[i]<a[j])
b[k++]=a[i++];
else if(a[i]==a[j])
b[k++]=a[i++];
else
b[k++]=a[j++],g[d]+=mid-i+1;
}
while(i<=mid)
b[k++]=a[i++];
while(j<=r)
b[k++]=a[j++];
for(i=l;i<=r;i++)
a[i]=b[i];
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0);
int i,j,q,x;
cin>>n;
nn=1<<n;
for(i=1;i<=nn;i++)
cin>>a[i],c[i]=a[i];
msort(a,1,nn,n,f);
reverse(c+1,c+nn+1);
msort(c,1,nn,n,z);
cin>>q;
while(q--)
{
cin>>x;
ll sum=0;
for(i=x;i>=1;i--)
swap(f[i],z[i]);
for(i=1;i<=n;i++)
sum=sum+f[i];
cout<<sum<<endl;
}
return 0;
} import java.util.Scanner;
//主要是逆序对这块用的归并最后几个过不了
public class Main {
static int[] nums = null;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
nums = new int[(int) Math.pow(2,n)];
for (int i = 0; i < nums.length; i++) {
nums[i] = scanner.nextInt();
}
int m = scanner.nextInt();
int[] count = new int[m];
for (int i = 0; i < count.length; i++) {
count[i] = scanner.nextInt();
}
for (int j : count) {
System.out.println(getnums((int) Math.pow(2, j)));
}
}
private static int getnums(int pow) {
int l = 0,r = l+pow-1;
while (l<r){
int flag = r;
while (l<flag){
int a = nums[l];
nums[l] = nums[flag];
nums[flag] = a;
l++;flag--;
}
l = r+1;
r = l+pow-1>=nums.length?nums.length-1:l+pow-1;
}
return reversePairs(nums);
}
public static int reversePairs(int[] nums) {
int len = nums.length;
if (len < 2) {
return 0;
}
int[] copy = new int[len];
for (int i = 0; i < len; i++) {
copy[i] = nums[i];
}
int[] temp = new int[len];
return reversePairs(copy, 0, len - 1, temp);
}
private static int reversePairs(int[] nums, int left, int right, int[] temp) {
if (left == right) {
return 0;
}
int mid = left + (right - left) / 2;
int leftPairs = reversePairs(nums, left, mid, temp);
int rightPairs = reversePairs(nums, mid + 1, right, temp);
if (nums[mid] <= nums[mid + 1]) {
return leftPairs + rightPairs;
}
int crossPairs = mergeAndCount(nums, left, mid, right, temp);
return leftPairs + rightPairs + crossPairs;
}
private static int mergeAndCount(int[] nums, int left, int mid, int right, int[] temp) {
for (int i = left; i <= right; i++) {
temp[i] = nums[i];
}
int i = left;
int j = mid + 1;
int count = 0;
for (int k = left; k <= right; k++) {
if (i == mid + 1) {
nums[k] = temp[j];
j++;
} else if (j == right + 1) {
nums[k] = temp[i];
i++;
} else if (temp[i] <= temp[j]) {
nums[k] = temp[i];
i++;
} else {
nums[k] = temp[j];
j++;
count += (mid - i + 1);
}
}
return count;
}
}
#include "bits/stdc++.h"
using namespace std;
using i64 = long long;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n; cin >> n;
int N = 1 << n;
vector<i64> order(n + 1), reorder(n + 1);
vector<int> a(N), b(N), temp(N);
for(int i = 0;i < N; i++) {
int x; cin >> x;
a[i] = b[N - i - 1] = x;
}
function<void(int, int, int)> dfs1 = [&](int l, int r, int stp) {
if(l == r) return ;
int m = (l + r) / 2;
dfs1(l, m, stp - 1);
dfs1(m + 1, r, stp - 1);
int p = l, q = m + 1;
for(int i = l;i <= r; i++) {
if((p <= m && a[p] <= a[q]) || q > r) temp[i] = a[p++];
else order[stp] += p - l, temp[i] = a[q++];
}
for(int i = l;i <= r; i++) a[i] = temp[i];
};
function<void(int, int, int)> dfs2 = [&](int l, int r, int stp) {
if(l == r) return ;
int m = (l + r) / 2;
dfs2(l, m, stp - 1);
dfs2(m + 1, r, stp - 1);
int p = l, q = m + 1;
for(int i = l;i <= r; i++) {
if((p <= m && b[p] <= b[q]) || q > r) temp[i] = b[p++];
else reorder[stp] += p - l, temp[i] = b[q++];
}
for(int i = l;i <= r; i++) b[i] = temp[i];
};
dfs1(0, N - 1, n);
dfs2(0, N - 1, n);
int q; cin >> q;
while(q--) {
int x; cin >> x;
for(int j = 1;j <= x; j++) swap(order[j], reorder[j]);
i64 ans = 0;
cout << accumulate(reorder.begin(), reorder.end(), 0) << '\n';
}
} // 使用归并排序的思想
// 记录下组内的逆序对和组间的逆序对
#include<iostream>
#include<vector>
using namespace std;
void merge_sort(vector<int> &vec, vector<int> &trans, vector<long long> &reverses, vector<long long> &equal, int start, int end, int degree) {
if(end - start == 1) {
return;
}
int mid = start + (end - start) / 2;
merge_sort(vec, trans, reverses, equal, start, mid, degree - 1);
merge_sort(vec, trans, reverses, equal, mid, end, degree - 1);
int l = start, r = mid, ptr = start;
while(l < mid && r < end) {
// 左边比右边大
if(vec[l] > vec[r]) {
reverses[degree] += (long long)(end - r);
trans[ptr++] = vec[l++];
} else if(vec[l] == vec[r]){
int num1 = 0, num2 = 0, tmp = l, t = vec[l];
while(tmp < mid && vec[tmp] == t) {
num1++;
tmp++;
}
while(r < end && vec[r] == t) {
num2++;
trans[ptr++] = vec[r++];
}
equal[degree] += (long long)num1 * (long long)num2;
} else{
trans[ptr++] = vec[r++];
}
}
while(l < mid)
trans[ptr++] = vec[l++];
while(r < end)
trans[ptr++] = vec[r++];
for(int i = start; i < end; ++i)
vec[i] = trans[i];
}
int main() {
int n, m, size, ops;
long long num, res = 0;
cin >> n;
size = 1 << n;
vector<int> vec(size, 0);
vector<int> trans(size, 0);
vector<long long> reverses(n, 0);
vector<long long> equal(n, 0);
vector<long long> num_pairs(n, 0);
for(int i = 0; i < n; ++i) {
num = 1 << i;
num_pairs[i] = num * num * (1 << (n - i - 1));
}
for(int i = 0; i < size; ++i)
cin >> vec[i];
merge_sort(vec, trans, reverses, equal, 0, size, n - 1);
cin >> m;
for(int i = 0; i < m; ++i) {
cin >> ops;
res = 0;
for(int j = ops - 1; j >= 0; --j) {
reverses[j] = num_pairs[j] - reverses[j] - equal[j];
}
for(int j = 0; j < n; ++j)
res += reverses[j];
cout << res << endl;
}
return 0;
} #include <iostream>
#include <vector>
#include <cassert>
#include <cmath>
using namespace std;
vector<long long> OrderCnt(21, 0);
vector<long long> reOrderCnt(21, 0);
void MergeSort(vector<long long>& vec, long long begin, long long end, int d) {
assert((end - begin) == (long long)pow(2, d));
if (begin == end || begin == end - 1)
return;
long long mid = (begin + end) / 2;
MergeSort(vec, begin, mid, d - 1);
MergeSort(vec, mid, end, d - 1);
vector<long long> nums(end - begin);
long long i = begin;
long long j = mid;
long long k = 0;
while (i < mid && j < end) {
if (vec[i] < vec[j]) {
OrderCnt[d] += (end - j);
nums[k++] = vec[i++];
}
else if (vec[i] > vec[j]) {
reOrderCnt[d] += (mid - i);
nums[k++] = vec[j++];
}
else if (vec[i] == vec[j]) {
long long tmp = j + 1;
while (tmp < end && vec[tmp] == vec[j])
tmp++;
OrderCnt[d] += (end - tmp);
nums[k++] = vec[i++];
}
}
while (i < mid)
nums[k++] = vec[i++];
while (j < end)
nums[k++] = vec[j++];
k = 0;
for (int i = begin; i < end; i++)
vec[i] = nums[k++];
return;
}
int main() {
int n;
cin >> n;
int len = pow(2, n);
vector<long long> vec(len);
for (long long i = 0; i < len; i++)
cin >> vec[i];
MergeSort(vec, 0, len, n);
long long m, q;
cin >> m;
while (m--) {
cin >> q;
for (int i = 0; i <= q; i++)
swap(OrderCnt[i], reOrderCnt[i]);
long long cnt = 0;
for (int i = 0; i <= n; i++)
cnt += reOrderCnt[i];
cout << cnt << endl;
}
return 0;
} //开始忽略了还有相等情况,直接用对数总和减去逆序对了。实际上考虑相等情况,应该是顺序与逆序交替。
#include <iostream>
#include <vector>
#include <numeric>
using namespace std;
//void mergesort(vector<int> &nums,int left,int right,vector<int> &dp,int n);
//dp[i]表示长度为2^i长度左右两侧的归并数目.归并排序。
void mergesort(vector<long long> &nums,int left,int right,vector<long long> &dp,int k) {//归并排序,计算逆序对数量
if(left>=right) return;
int mid=(right+left)/2;
mergesort(nums,left,mid,dp,k-1);
mergesort(nums,mid+1,right,dp,k-1);
int l=left,r=mid+1;
while(l<=mid){
while(r<=right&&nums[l]>nums[r]){
++r;
}
dp[k]+=r-mid-1;
++l;
}
vector<long long> temp(right-left+1);
l=left,r=mid+1;
int p=0;
while(l<=mid||r<=right){
if(l>mid){
temp[p++]=nums[r++];
}
else if(r>right){
temp[p++]=nums[l++];
}
else{
if(nums[l]<nums[r]){
temp[p++]=nums[l++];
}
else{
temp[p++]=nums[r++];
}
}
}
for(int i=0;i<temp.size();++i){
nums[left+i]=temp[i];
}
}
int main(){
int n;
cin>>n;
int len=1<<n;
vector<long long> v(len);
for(int i=0;i<len;++i){
cin>>v[i];
}
vector<long long> dp(n+1,0);
vector<long long> rdp(n+1,0);
vector<long long> rv(v.rbegin(),v.rend());
mergesort(v,0,len-1,dp,n); //计算逆序对。dp[n]表示间隔至少为2^(n-1)的逆序对。对应归并排序每次递归后子序列长度。
mergesort(rv,0,len-1,rdp,n); //计算顺序对,翻转数组则求逆序等于求原数组顺序
// for(int i=0;i<=n;++i){
// cout<<dp[i];
// }
//cout<<endl;
int m;
cin>>m;
int q;
for(int i=0;i<m;++i){
cin>>q;
long long res=0;
for(int i=1;i<=n;++i){
if(i<=q) swap(dp[i],rdp[i]);
res+=dp[i];
// cout<<endl;
}
cout<<res<<endl;
}
return 0;
} clear
try
n = input('');
s = input('','s');
m = input('');
k = input('','s');
s = str2num(s);
k = str2num(k);
ss = zeros(m+1,2^n);
ss(1,:) = s;
for i1 = 1 : m
q = zeros(2^(k(i1)),2^n/2^(k(i1)));
q(:) = ss(i1,:);
q = q';
q = q(:,end:-1:1);
q = q';
ss(i1+1,:) = q(:);
end
y = zeros(m+1,1);
for i2 = 1 : 2^n-1
y = y + sum(ss(:,i2+1:end)<ss(:,i2),2);
end
fprintf('%d\n',y(2:end));
catch
end