观察可以发现: できない
对于这样的两列表格,一次 2x2 的正方形 180° 旋转相当于 左上与右下、左下与右上交换
而这样的交换不会改变什么?不会改变任意一列的两个数字!
但会改变这两个数字的位置关系,旋转一次就上下颠倒一次
所以我们得到了第一个判断无解的条件:
若 原状态 任意一列的两个数字在 目标状态 中位置不是在同一列,显然无解
接着,在排除了以上无解情况后,我们又可以 通过看题解 发现:
原状态 任意一列的两个数字在 目标状态 中对应的位置不同,解的存在性也会改变!
2
/
3
2/3
2/3 要转化成
3
/
2
3/2
3/2 中间旋转的次数显然是 奇数次 !
同理,若 原状态 到 目标状态 的列上下关系没变,旋转次数就是 偶数次
若不满足这 奇偶性 ,显然无解
—————————————————————————————————————
综上,我们终于探讨完了有无解的判断
那怎么求 最少 旋转次数呢?
可以观察到,同一列的两个数字怎么旋转都是捆绑在一起的、不会变动,所以可以把 一列 当成 一个数字
这样问题就转化成:
原状态 的一列数字 转化成 目标状态 的一列数字,问转化的最小步数(转化方式是交换任意相邻的两列数字)
通过经验我们可知:在一个序列(由母版映射过来)里求逆序对的数量 == 这个序列从母版转化过来的最小步数
所以,上代码:
#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1000010, M = 110, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
struct arr
{
int row, col;
}ch[N << 1];
int b[3][N], z[N], tmp[N];
bool check() {
for (int j = 1; j <= n; j++) {
int b1 = b[1][j], b2 = b[2][j];
if (ch[b1].col != ch[b2].col)return false;
}
for (int j = 1; j <= n; j++) {
int b1 = b[1][j];
if (ch[b1].row == 1) {
if (ch[b1].col % 2 != j % 2)return false;
}
else {
if (ch[b1].col % 2 == j % 2)return false;
}
}
return true;
}
ll gui_sort(int l, int r) {
if (l >= r)return 0;
int mid = l + r >> 1;
ll cnt = gui_sort(l, mid) + gui_sort(mid + 1, r);
int i = l, j = mid + 1, k = l;
while (i <= mid && j <= r)
{
if (z[i] <= z[j])tmp[k++] = z[i++];
else {
cnt += (ll)mid - i + 1;
tmp[k++] = z[j++];
}
}
while (i <= mid)tmp[k++] = z[i++];
while (j <= r)tmp[k++] = z[j++];
for (int i = l; i <= r; i++)z[i] = tmp[i];
return cnt;
}
int main() {
cinios;
cin >> n;
for (int i = 1; i <= 2; i++)
for (int j = 1; j <= n; j++) {
int t;
cin >> t;
ch[t] = { i,j };
}
for (int i = 1; i <= 2; i++)
for (int j = 1; j <= n; j++)
cin >> b[i][j];
if (!check()) {
cout << "dldsgay!!1";
return 0;
}
for (int j = 1; j <= n; j++)
z[j] = ch[b[2][j]].col;
cout << gui_sort(1, n);
return 0;
}
—————————————————————————————————————
更简便的一种判断方法,摘自洛谷题解
所有数字可以分成两种状态,
W
和
M
W 和 M
W和M
只要有 W 的数字跑到了 M 的位置,或者反之,就可以说明无解
代码:
#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul (u << 1)
#define ur (u << 1 | 1)
#define fx first
#define fy second
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1000010, M = 110, MM = 3000010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S, D;
int st[N << 1];
int a[N][2], b[N][2], z[N], tmp[N];
ll gui_sort(int l, int r) {
if (l >= r)return 0;
int mid = l + r >> 1;
ll cnt = gui_sort(l, mid) + gui_sort(mid + 1, r);
int i = l, j = mid + 1, k = l;
while (i <= mid && j <= r)
{
if (z[i] <= z[j])tmp[k++] = z[i++];
else {
cnt += (ll)mid - i + 1;
tmp[k++] = z[j++];
}
}
while (i <= mid)tmp[k++] = z[i++];
while (j <= r)tmp[k++] = z[j++];
for (int i = l; i <= r; i++)z[i] = tmp[i];
return cnt;
}
int main() {
cinios;
cin >> n;
for (int i = 0; i < 2; i++)
for (int j = 1; j <= n; j++)cin >> a[j][i];
for (int i = 0; i < 2; i++)
for (int j = 1; j <= n; j++)cin >> b[j][i];
for (int i = 1; i <= n; i++)
st[a[i][i & 1]] = i;
for (int i = 1; i <= n; ++i) {
if (st[b[i][i & 1]])z[i] = st[b[i][i & 1]];
else {
cout << "dldsgay!!1";
return 0;
}
}
cout << gui_sort(1, n);
return 0;
}
简洁优美
|