題目鏈接: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;
}