在上上上篇题解中有两个重要结论:

- 任意一个排列一定可以唯一的分解成若干个互不相交的置换环并集
-
假设长度为
的排列有
个置换环,那么交换任意两个元素使得排列升序的最少操作次数为
次
现在补充两个排列与逆序对的结论:
- 一个排列中,交换任意两个元素,逆序对数的奇偶性一定改变
-
排列的逆序对数与
的奇偶性相同
证明第一个结论:
-
如果交换的位置相邻,那么逆序对数加
或者减
,那么奇偶性改变
-
如果交换的位置不相邻,设交换的两个位置之间有
个元素,那么两个位置相当于与中间
个元素都进行了一次交换,所以是
次交换,再加上两个位置的交换,所以是
次交换,所以奇偶性改变
证明第二个结论:
将排列通过交换顺序使其升序:
-
如果可以交换任意两个位置,那么最小操作次数是
次
- 如果只能是交换相邻两个位置,那么最小操作次数是排列的逆序对数次
可见最终的目的是使得排列升序,而升序的逆序对数是
,所以排列的逆序对数与
的奇偶性相同
思考
的
种排列:
,
,
,
,
,
其中
,
,
这
个排列可以通过操作相互到达,其逆序对数分别为
其中
,
,
这
个排列可以通过操作相互到达,其逆序对数分别为
可以分析出执行操作时,逆序对数的奇偶性没有发生变化,故直接判断
的逆序对数奇偶性即可
哦,不一定是排列,可能是
这种,再和上面一样的分析,发现逆序对数可以为
,可以消除奇偶性
那么如果
的逆序对数为偶数,直接输出
,否则判断是否有两个相同的数,如果有输出
,否则输出
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 500010;
int a[N], b[N], sum;
void quick_sort(int l, int r){
if(l >= r) return ;
int mid = (l + r) / 2;
quick_sort(l, mid);
quick_sort(mid + 1, r);
int i = l, j = mid + 1, k = l;
while(i <= mid && j <= r){
if(a[i] <= a[j]) b[k ++] = a[i ++];
else{
b[k ++] = a[j ++];
sum += mid - i + 1;
}
}
while(i <= mid) b[k ++] = a[i ++];
while(j <= r) b[k ++] = a[j ++];
for(int i = l; i <= r; i ++) a[i] = b[i];
}
void solve(){
int n; cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
sum = 0;
quick_sort(1, n);
if(sum & 1){
for(int i = 1; i <= n - 1; i ++){
if(a[i] == a[i + 1]){
cout << "YES" << endl;
return ;
}
}
cout << "NO" << endl;
}
else cout << "YES" << endl;
return ;
}
signed main(){
HelloWorld;
int tt = 1;
cin >> tt;
while(tt --) solve();
return 0;
}
区间
翻转时,逆序对数的变化是
,所以累加初始状态的逆序对数,判断奇偶性即可
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 2000;
int n, m, a[N], b[N];
int sum;
void quick_sort(int l, int r){
if(l >= r) return;
int mid = (l + r) / 2;
quick_sort(l, mid);
quick_sort(mid + 1, r);
int i = l, j = mid + 1, k = l;
while(i <= mid && j <= r){
if(a[i] <= a[j]) b[k ++] = a[i ++];
else{
b[k ++] = a[j ++];
sum += mid - i + 1;
}
}
while(i <= mid) b[k ++] = a[i ++];
while(j <= r) b[k ++] = a[j ++];
for(int i = l; i <= r; i ++) a[i] = b[i];
}
void solve(){
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
sum = 0;
quick_sort(1, n);
cin >> m;
while(m --){
int l, r; cin >> l >> r;
sum += (r - l + 1) * (r - l) / 2;
if(sum & 1) cout << "odd" << endl;
else cout << "even" << endl;
}
return ;
}
signed main(){
HelloWorld;
int tt = 1;
while(tt --) solve();
return 0;
}
交换任意两个元素,排列的逆序对数奇偶性发生变化,
-
当
为奇数时,
为奇数,
为偶数
-
当
为偶数时,
为偶数,
为奇数
所以一开始从
到
的自然序列排列进行
或
次交换操作后,逆序对数的奇偶性与
的奇偶性以及操作的次数的奇偶性有关,现在已知
的奇偶性,也可以求出操作后排列的逆序对数的奇偶性,所以反推操作次数的奇偶性即可
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 1000100;
int n, a[N], b[N];
int sum;
void quick_sort(int l, int r){
if(l >= r) return;
int mid = (l + r) / 2;
quick_sort(l, mid);
quick_sort(mid + 1, r);
int i = l, j = mid + 1, k = l;
while(i <= mid && j <= r){
if(a[i] <= a[j]) b[k ++] = a[i ++];
else{
b[k ++] = a[j ++];
sum += mid - i + 1;
}
}
while(i <= mid) b[k ++] = a[i ++];
while(j <= r) b[k ++] = a[j ++];
for(int i = l; i <= r; i ++) a[i] = b[i];
}
void solve(){
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
sum = 0;
quick_sort(1, n);
if(n & 1){
if(sum & 1) cout << "Petr" << endl;
else cout << "Um_nik" << endl;
}
else{
if(sum & 1) cout << "Um_nik" << endl;
else cout << "Petr" << endl;
}
return ;
}
signed main(){
HelloWorld;
int tt = 1;
while(tt --) solve();
return 0;
}
和题目一有些类似,不多写了
总代码:
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;
const int N = 200010;
int n, a[N], b[N], a1[N], b1[N];
int sum1, sum2;
void quick_sort_a(int l, int r){
if(l >= r) return ;
int mid = (l + r) / 2;
quick_sort_a(l, mid);
quick_sort_a(mid + 1, r);
int i = l, j = mid + 1, k = l;
while(i <= mid && j <= r){
if(a[i] <= a[j]) a1[k ++] = a[i ++];
else{
a1[k ++] = a[j ++];
sum1 += mid - i + 1;
}
}
while(i <= mid) a1[k ++] = a[i ++];
while(j <= r) a1[k ++] = a[j ++];
for(int i = l; i <= r; i ++) a[i] = a1[i];
}
void quick_sort_b(int l, int r){
if(l >= r) return ;
int mid = (l + r) / 2;
quick_sort_b(l, mid);
quick_sort_b(mid + 1, r);
int i = l, j = mid + 1, k = l;
while(i <= mid && j <= r){
if(b[i] <= b[j]) b1[k ++] = b[i ++];
else{
b1[k ++] = b[j ++];
sum1 += mid - i + 1;
}
}
while(i <= mid) b1[k ++] = b[i ++];
while(j <= r) b1[k ++] = b[j ++];
for(int i = l; i <= r; i ++) b[i] = b1[i];
}
void solve(){
cin >> n;
for(int i = 1; i <= n; i ++) cin >> a[i];
for(int i = 1; i <= n; i ++) cin >> b[i];
sum1 = sum2 = 0;
quick_sort_a(1, n);
quick_sort_b(1, n);
for(int i = 1; i <= n; i ++){
if(a[i] != b[i]){
cout << "No" << endl;
return ;
}
}
if((sum1 & 1) == (sum2 & 1)) cout << "Yes" << endl;
else{
for(int i = 1; i <= n - 1; i ++){
if(a[i] == a[i + 1]){
cout << "Yes" << endl;
return ;
}
}
cout << "No" << endl;
}
return ;
}
signed main(){
HelloWorld;
int tt = 1;
while(tt --) solve();
return 0;
}



京公网安备 11010502036488号