** luoguP4005 小 Y 和地铁**
** 分析**
很有意思的一道搜索+贪心题。
首先在这条路线上只出现过一次的点可以不管他。
所以我们只考虑两两匹配的情况。
一共有以下八种情况
暴力所有情况,令
m
=
n
2
m=\frac{n}{2}
m=2n
复杂度
O
(
m
8
m
)
O(m8^m)
O(m8m)
考虑优化,发现图
(
1
,
2
)
,
(
3
,
4
)
(
5
,
6
)
(
7
,
8
)
(1,2),(3,4)(5,6)(7,8)
(1,2),(3,4)(5,6)(7,8)形成了环。这意味着某条直线上的闭合曲线与组内的两条线交点个数相同,所以放哪种实际上没差。
复杂度
O
(
m
4
m
)
O(m4^m)
O(m4m)
考虑下面这种情况
发现他们把直线的后半部分包住了,也就是左端点在后半部分的点和它们俩的交点个数相同。
所以按左端点排序,每次贪心选最优秀的哪一种即可。
复杂度
O
(
m
2
m
)
O(m2^m)
O(m2m)
复杂度其实已经足够优秀,再优化不能从图下手,考虑能不能怼掉那个
m
m
m
计数的时候发现对于
4
∗
4
4*4
4∗4种情况实际上是一个数点问题,用树状数组维护,复杂度
O
(
2
m
l
o
g
m
)
O(2^mlogm)
O(2mlogm)(这复杂度也是够奇葩的)
然后就过啦。
** 代码**
#include<bits/stdc++.h>
const int N = 101;
int ri() {
char c = getchar(); int x = 0, f = 1; for(;c < '0' || c > '9'; c = getchar()) if(c == '-') f = -1;
for(;c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) - '0' + c; return x * f;
}
int tp, n, ans, L[N], R[N], bin[25];
struct Data {
int l, r;
bool operator < (Data a) const {return l < a.l;}
}a[N];
struct BIT{
int t[N];
void Add(int x, int w) {
for(;x <= n; x += x&-x)
t[x] += w;
}
int Que(int x) {
int r = 0;
for(;x; x -= x&-x)
r += t[x];
return r;
}
int Que(int L, int R) {return Que(R) - Que(L - 1);}
}up, down;
void Dfs(int i, int s) {
if(i == tp)
return void(ans = std::min(ans, s));
if(s >= ans) return ;
int r1 = up.Que(a[i].l, a[i].r);
int r2 = up.Que(a[i].r, n) + down.Que(a[i].l, n);
up.Add(a[i].r, 1);
Dfs(i + 1, s + std::min(r1, r2));
up.Add(a[i].r, -1);
r1 = down.Que(a[i].l, a[i].r);
r2 = down.Que(a[i].r, n) + up.Que(a[i].l, n);
down.Add(a[i].r, 1);
Dfs(i + 1, s + std::min(r1, r2));
down.Add(a[i].r, -1);
}
int main() {
bin[0] = 1; for(int i = 1;i <= 22; ++i) bin[i] = bin[i - 1] << 1;
for(int T = ri(); T--;) {
n = ri(); tp = 0;
for(int i = 1;i <= n; ++i) L[i] = R[i] = 0;
for(int i = 1;i <= n; ++i) {
int x = ri();
if(!L[x]) L[x] = i;
else R[x] = i;
}
for(int i = 1;i <= n; ++i)
if(L[i] && R[i])
a[tp].l = L[i], a[tp++].r = R[i];
std::sort(a, a + tp);
ans = 1e9; Dfs(0, 0);
printf("%d\n", ans);
}
return 0;
}