D2. Seating Arrangements (hard version)
题目传送门:
题面:
题目大意:
这题目很搞。
就是给你
n
∗
m
n*m
n∗m的网格,每个格子有自己的编号,编号方法见上图。
再给你
n
∗
m
n*m
n∗m个数字,要求数量越大的数字要在编号越大的格子里。然后定义
a
n
s
ans
ans。
好难讲啊,就是每个数字要按照给定顺序到该去的地方,每途径一个非空网格就要
a
n
s
+
+
;
ans++;
ans++;问最终整个网格
a
n
s
ans
ans是多少。
思路:
哎,当时比赛时候心态不好,其实肯定能做出来的!
只能说还是要冷静点。
多推两个就能发现贪心方法。
实际上有一点必须要明确最终的排列方式是确定且唯一的。
所以所有排列都是从小往大放,这是确定的,唯一可以有安排余地的是:次序不同但大小一样的数字。
贪心策略主要是对id从小到大
or 从大到小排序
。
具体看代码。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 310;
struct Node {
int x, id;
} a[maxn * maxn];
bool cmp1(Node x, Node y) {
if (x.x == y.x) return x.id < y.id;
return x.x < y.x;
}
bool cmp2(Node x, Node y) {
if (x.x == y.x) return x.id > y.id;
return x.x < y.x;
}
int main() {
cin.tie(0);
ios::sync_with_stdio(false);
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
for (int i = 1; i <= n * m; i++) {
cin >> a[i].x;
a[i].id = i;
}
sort(a + 1, a + 1 + n * m, cmp1);
int ans = 0;
for (int i = 1; i <= n; i++) {
sort(a + 1 + (i - 1) * m, a + 1 + i * m, cmp2);
int l = (i - 1) * m + 1, r = i * m;
for (int j = l; j <= r; j++)
for (int k = l; k < j; k++)
if (a[j].id > a[k].id) ans++;
}
cout << ans << endl;
}
}