*注意:这套题目题面请在loj / uoj查看

Problem A 小 Y 和地铁

题目传送门

  传送点L

  传送点U

题目大意

  小Y乘坐0号地铁线路。城市中有不超过$n + 1$条地铁线路。地铁线路不会自交,两条不同的地铁线路最多有两个交点,交点处一定是换乘站,同时也没有三条地铁线路交于一点。小Y经过了$n$个换乘站,依次给通过它们能过换到的另一条地铁线路的编号,问城市中之多还有多少个换乘站。

  显然只与0号地铁相交1次的地铁线路没有用。

  下面的点指的是一个换乘站,它的颜色编号指的是它能够换乘的另一条地铁的编号。

  然后认真画图可以发现,连接两个颜色相同的点,实际上会将整个图划分成两个区域,所以总共有四种不同的连线方法:

清华集训2017 Day 2简要题解

  于是有了$2^{45}\times 45$的优秀做法。

  我们考虑从小到达考虑每种颜色的第一个点,我们发现按照对后面的贡献可以将决策分为两种:

清华集训2017 Day 2简要题解

  每一行的两种状态对后面的影响是一样的,所以我们可以对每一行的两种决策对当前的影响取最小值继续进行搜索。

  这样时间复杂度降为$O(Tn2^{n/2})$。

  加一个最优性剪枝即可通过。

Code

 1 /**
 2  * loj
 3  * Problem#2323
 4  * Accepted
 5  * Time: 3349ms
 6  * Memory: 252k
 7  */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11 
12 const int N = 50;
13 
14 int T;
15 int n;
16 int ar[N], br[N], hs[N];
17 int cup, cdn;
18 int ups[N], dns[N];
19 
20 inline void init() {
21     scanf("%d", &n);
22     memset(hs, 0, sizeof(hs));
23     memset(ar, 0, sizeof(ar));
24     for (int i = 1; i <= n; i++) {
25         scanf("%d", br + i);
26         ar[hs[br[i]]] = i, hs[br[i]] = i;
27     }
28 }
29 
30 int res;
31 void dfs(int p, int cur) {
32     if (cur >= res)
33         return ;
34     if (p > n) {
35         res = cur;
36         return ;
37     }
38     if (!ar[p])
39         dfs(p + 1, cur);
40     else {
41         int cnt1 = 0, cnt2 = 0;
42         for (int i = 0; i < cup; i++) {
43             cnt1 += (ups[i] > p && ups[i] < ar[p]);
44             cnt2 += (ups[i] > ar[p]);
45         }
46         for (int i = 0; i < cdn; i++)
47             cnt2 += (dns[i] > p);
48         ups[cup++] = ar[p];
49         dfs(p + 1, cur + min(cnt1, cnt2));
50 
51         cup--, cnt1 = 0, cnt2 = 0;
52         for (int i = 0; i < cdn; i++) {
53             cnt1 += (dns[i] > p && dns[i] < ar[p]);
54             cnt2 += (dns[i] > ar[p]);
55         }
56         for (int i = 0; i < cup; i++)
57             cnt2 += (ups[i] > p);
58         dns[cdn++] = ar[p];
59         dfs(p + 1, cur + min(cnt1, cnt2));
60         cdn--;
61     }
62 }
63 
64 inline void solve() {
65     res = 233333;
66     dfs(1, 0);
67     printf("%d\n", res);
68 }
69 
70 int main() {
71     scanf("%d", &T);
72     while (T--) {
73         init();
74         solve();
75     }
76     return 0;
77 }
Problem A

相关文章: