# 2018.9.25 NOIP模拟赛

*注意：这套题目应版权方要求，不得公示题面。

#### 从这里开始

表示十分怀疑出题人水平，C题数据和标程都是错的。有原题，差评。

### Problem A XOR

最小异或生成树

出门左拐Codeforces 888G。

### Code

  1 #include <iostream>
2 #include <cstdlib>
3 #include <cstdio>
4 #include <vector>
5 #ifndef WIN32
6 #define Auto "%lld"
7 #else
8 #define Auto "%I64d"
9 #endif
10 using namespace std;
11 typedef bool boolean;
12 #define ll long long
13
14 const int Mask = 1 << 30;
15 const signed int inf = (signed) (~0u >> 1);
16
17 typedef class TrieNode {
18     public:
19         TrieNode* ch[2];
20 }TrieNode;
21
22 TrieNode pool[3300000];
23 TrieNode* top;
24
25 TrieNode* newnode() {
26     top->ch[0] = top->ch[1] = NULL;
28 }
29
30 typedef class Trie {
31     public:
32         TrieNode* rt;
33
34         void reset() {
35             top = pool;
36             rt = newnode();
37         }
38
39         void insert(int x) {
40             TrieNode* p = rt;
43                 int c = ((x & mask) ? (1) : (0));
44                 if (!p->ch[c])
45                     p->ch[c] = newnode();
46                 p = p->ch[c], mask >>= 1;
47             }
48         }
49
50         int query(int x) {
51             TrieNode* p = rt;
54                 int c = ((x & mask) ? (1) : (0));
55                 if (p->ch[c])
56                     p = p->ch[c];
57                 else
58                     p = p->ch[c ^ 1], rt += mask;
60             }
61             return rt;
62         }
63 }Trie;
64
65 int n;
66 int* ar;
67 Trie tr;
68
69 inline void init() {
70     scanf("%d", &n);
71     ar = new int[(n + 1)];
72     for (int i = 1; i <= n; i++)
73         scanf("%d", ar + i);
74 }
75
76 ll dividing(int tem, vector<int>& vs) {
77     if (!tem)
78         return 0;
79     vector<int> v0, v1;
80     for (int i = 0; i < (signed) vs.size(); i++)
81         if (vs[i] & tem)
82             v1.push_back(vs[i]);
83         else
84             v0.push_back(vs[i]);
85     if (!v0.size())
86         return dividing(tem >> 1, v1);
87     if (!v1.size())
88         return dividing(tem >> 1, v0);
89     tr.reset();
90     for (int i = 0; i < (signed) v0.size(); i++)
91         tr.insert(v0[i]);
92     int rt = inf;
93     for (int i = 0, cmp; i < (signed) v1.size(); i++) {
94         cmp = tr.query(v1[i]);
95         rt = min(cmp, rt);
96     }
97     return rt * 1ll + dividing(tem >> 1, v0) + dividing(tem >> 1, v1);
98 }
99
100 inline void solve() {
101     vector<int> vs;
102     for (int i = 1; i <= n; i++)
103         vs.push_back(ar[i]);
105 }
106
107 int main() {
108     freopen("A.in", "r", stdin);
109     freopen("A.out", "w", stdout);
110     init();
111     solve();
112     return 0;
113 }
Problem A

### Problem B GCD

最小gcd生成树，点权1~n。

加速Kruskal的过程。边排序的时候把编号也作为关键字。

### Code

 1 #include <iostream>
2 #include <cstdlib>
3 #include <cstdio>
4 using namespace std;
5 typedef bool boolean;
6
7 int n;
8
9 inline void init() {
10     scanf("%d", &n);
11 }
12
13 int *uf;
14
15 int find(int x) {
16     return (uf[x] == x) ? (x) : (uf[x] = find(uf[x]));
17 }
18
19 long long res = 0;
20 inline void solve() {
21     uf = new int[(n + 1)];
22     for (int i = 1; i <= n; i++)
23         uf[i] = i;
24     for (int i = n >> 1; i; i--) {
25         for (int j = i << 1; j <= n; j += i) {
26             if (find(i) != find(j)) {
27                 res += i;
28                 uf[find(i)] = find(j);
29             }
30         }
31     }
32     cout << res << endl;
33 }
34
35 int main() {
36     freopen("B.in", "r", stdin);
37     freopen("B.out", "w", stdout);
38     init();
39     solve();
40     return 0;
41 }
Problem B

### Problem C SEG

平面的三角剖分。问边数的奇偶性。

mmp，最开始理解错题意了。是说咋觉得不可做。

可以求出凸包，设凸包上的点数和边数均为$m$。然后设顶点总数为$V$，边数为$E$，分割成的三角形的个数为$x$。

则根据欧拉公式有：$x + 1 + V - \frac{3x + m}{2} = 2$

解得：$x = 2n - m - 2$，由此得到边数。

另外这道题数据似乎对极角序不是很友好。

### Code

 1 #include <algorithm>
2 #include <iostream>
3 #include <cstdlib>
4 #include <cstdio>
5 #include <cmath>
6 #ifndef WIN32
7 #define Auto "%lld"
8 #else
9 #define Auto "%I64d"
10 #endif
11 using namespace std;
12 typedef bool boolean;
13
14 #define ll long long
15
16 typedef class Point {
17     public:
18         ll x, y;
19
20         Point(ll x = 0.0, ll y = 0.0):x(x), y(y) {    }
21
22         boolean operator < (Point b) const {
23             if (x ^ b.x)
24                 return x < b.x;
25             return y < b.y;
26         }
27 }Point, Vector;
28
29 Point operator - (Point a, Point b) {
30     return Point(a.x - b.x, a.y - b.y);
31 }
32
33 ll cross(Point a, Point b) {
34     return a.x * b.y - a.y * b.x;
35 }
36
37 int n, m;
38 Point* ps;
39
40 inline void init() {
41     scanf("%d", &n);
42     ps = new Point[(n + 1)];
43     for (int i = 1; i <= n; i++)
44         scanf(Auto""Auto, &ps[i].x, &ps[i].y);
45 }
46
47 int st;
48 Point* tp;
49
50 inline void solve() {
51     tp = new Point[(n + 2)];
52     sort(ps + 1, ps + n + 1);
53     for (int i = 1; i <= n; i++) {
54         while (st > 1 && cross(tp[st] - tp[st - 1], ps[i] - tp[st]) <= 0)
55             st--;
56         tp[++st] = ps[i];
57     }
58     m += st - 2, st = 0;
59     for (int i = n; i; i--) {
60         while (st > 1 && cross(tp[st] - tp[st - 1], ps[i] - tp[st]) <= 0)
61             st--;
62         tp[++st] = ps[i];
63     }
64     m += st;
65
66     int A = ((n << 1) - m) - 2;
67     int E = (3 * A + m) >> 1;
68     if (E & 1)
69         puts("Alice");
70     else
71         puts("Bob");
72 }
73
74 int main() {
75     init();
76     solve();
77     return 0;
78 }
Problem C
posted @ 2018-09-25 16:40 阿波罗2003 阅读(...) 评论(...) 编辑 收藏