题目链接:csoj | M. Minimal and Maximal XOR Sum (scnu.edu.cn)
解题思路:
最小值:每次操作的区间长度为2,即交换两个相邻数,每次异或2(10),故最小值肯定为2(10)或0(00),如果是偶排序最小值是0,奇排序最小值就是2。
最大值:
操作1:任选一个长度为 k 的区间,将其翻转,然后可以再利用k(k-1)/2次交换相邻两个数的操作再将这个区间翻转回去,相当于什么操作都没有做,而却多异或了一个 k 和 k(k-1)/2 个2
注意:当k为2^1即2时,操作1时无意义的,相邻两个数翻转再翻转,两次异或相同值2,sum不变。
当k为2^0即1时,l=r,故第一位肯定能变为1
故最大值( 位数为 n的二进制位数)只有第二位是有可能1有可能0(取决于最小值时该位是1还是0),其它位都可以直接变为1。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N], cnt, tmp[N];void merge_sort(int l,int r)
{if(l >= r) return;int mid = (l + r) >> 1;merge_sort(l, mid);merge_sort(mid + 1, r);int i = l, j = mid + 1, k = 0;while(i <= mid && j <= r){if(a[i] <= a[j]) tmp[k++] = a[i++];else{cnt += (mid - i + 1);tmp[k++] = a[j++];}}while(i <= mid) tmp[k++] = a[i++];while(j <= r) tmp[k++] = a[j++];for(int i = l, j = 0; i <= r; i++, j++){a[i] = tmp[j];}
}
int main(){int T;scanf("%d", &T);while(T--){int n;scanf("%d",&n);for(int i = 0; i < n; i++) scanf("%d", &a[i]);if (n == 1)//特判n=1 {printf("0 1\n");continue;}cnt = 0;//维护逆序对数量 int ans = 0;int t = n;while(t)//计算n的位数 {t >>= 1;ans++;}ans = (1 << ans) - 1;//计算ans位全是1的值 merge_sort(0, n - 1);//用归并排序求逆序对数,还可以用树状数组 if (cnt % 2 == 0) printf("0 %d\n", ans - 2);else printf("2 %d\n", ans);;} return 0;
}