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;
 27     return top++;
 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;
 41             int mask = Mask;
 42             while (mask) {
 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;
 52             int mask = Mask, rt = 0;
 53             while (mask) {
 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;
 59                 mask >>= 1;
 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]);
104     printf(Auto, dividing(Mask, vs));
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

转载于:https://www.cnblogs.com/yyf0309/p/9700319.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值