10.4 广州集训 Day3

bst

【问题描述】
   二叉查找树是一种特殊的二叉树(每个节点最多只有两个儿子的树)。树的每个节点上存有一个唯一的值,并且满足:这个节点的左子树内所有点的值都比这个节点的值小,且右子树内所有点的值都比这个节点的值要大。
   对于一棵二叉查找树T,我们可以将一个值为x的新点插入T中,且保持树的性质。
   算法如下:

10.4 广州集训 Day3_第1张图片

 

   需要将x插入树T时,执行insert(x, T.root) 。
   现在有N个数需要插入一棵空树中。给定插入序列,请在每个元素被插入之后,输出所有节点的深度总和(根的深度为0)。

【输入格式】
  输入的第一行一个整数 n,表示序列长度。
  以下 n 行是序列中的数字,这些数字是各不相同的,在[1, n]区间。
【输出格式】
  输出 n 行,第 i 行整数表示第 i 个数插入树后,至这个节点的节点深度总和。
【样例输入】
8
3
5
1
6
8
7
2
4
【样例输出】
0
1
2
4
7
11
13
15
【数据规模与约定】
  对于 50%的数据, 满足N ≤ 1000
  对于100%的数据,满足N ≤ 3 ∗ 10^5 。

 

Solution:

  双向链表+DP。(也可以说是个模拟)

  和字面意思上一样是一个treap。

  我们考虑:当x=a[i]被插入的时候,假设T(二叉搜索树)中比x小的最大元素是p,比x大的最小元素是q。显然,p,q一定相连(可以证明)。

  (证明:p,q之间不存在其他元素,谁在父亲取决于谁先插入。)

  我们设f[i]表示x插入的深度,可得f[i]=Max(f[p],f[q])+1。

  即转化为求p,q。

  怎么求呢?

  可以用双向链表存1~n,每次删除一个元素,删除时的前驱和后继就是p,q。

  这个问题就解决了。(其实也就是模拟一下treap)

 

Other:

  现场还有大佬对着排序数组按时间戳建笛卡尔树A了此题,大概不会打...

 1 #include 
 2 
 3 #define MAXN 300005
 4 
 5 int n;
 6 int a[MAXN];
 7 int prev[MAXN], next[MAXN];
 8 int u[MAXN], v[MAXN];
 9 int deep[MAXN];
10 
11 int main(void)
12 {
13 
14     scanf("%d", & n);
15     for (int i = 1; i <= n; ++i)
16         scanf("%d", a + i);
17         
18     for (int i = 1; i <= n; ++i)
19     {
20         prev[i]  = i - 1;
21         next[i] = i + 1;
22     }
23 
24     int x;
25     for (int i = n; i > 1; --i)
26     {
27         x = a[i];
28         u[x] = prev[x];
29         v[x] = next[x];
30         next[prev[x]] = next[x];
31         prev[next[x]] = prev[x];
32     }
33 
34     long long sum = 0;
35     for (int i = 1; i <= n; ++i)
36     {
37         x = a[i];
38         
39         if ((u[x] >= 1) && (u[x] <= n))
40             if (deep[x] < deep[u[x]] + 1)
41                 deep[x] = deep[u[x]] + 1;
42         if ((v[x] >= 1) && (v[x] <= n))
43             if (deep[x] < deep[v[x]] + 1)
44                 deep[x] = deep[v[x]] + 1;
45         
46         sum += deep[a[i]];
47         
48         printf("%lld\n", sum);
49     }
50 
51     return 0;
52 }

 

ctsc:

【问题描述】
  n 人参加信息学竞赛,共有 m 道题。现在比赛已经结束,评分正在进行中,对于已经结束评测的试题,已知每名考生这道题的答案是否正确,对于未结束评测的试题,只知道每名考生是否提交答案。每个题分数固定,提交正确的答案的考生可以得到这一题的分数,分数越高排名越靠前,分数相同编号小的考生排名靠前。这 n 人中,排名最靠前的 s 人将获得入选代表队的资格,而这 s 个中将通过最终的科学委员会面试选出其中的 t 个人。输入当前的评测信息(包括是否ᨀ交,以及已经评测部分的是否正确)以及每道题的分值,问最终的 t 人代表队共有多少种组队的可能。

【输入格式】
  输入文件第一行是 m,接下去 m 行每行一个整数来表示每道题目的分值(整数是正的表示该题已经评测,否则表示该题尚未评测,该题目的分值为这个整数的绝对值)。然后是一个整数 n,接下去是一个 n 行 m 列的字母阵,字母阵只包含 YN 两种字母(Yes or No),如果第 i 题已经完成评测,那么这个字母矩阵中第 j 行第 i 列的表示第 j 名选手的第 i 题是否已经得分;如果第 i 题尚未完成评测,那么这个字母矩阵中第 j 行第 i 列的表示第 j 名选手的第 i 题是否提交了解答。接下来两个整数s,t如题意。

【输出格式】
  输出文件只有一行,即为最终的 t 人代表队的组队方案数。

【样例输入】

2
1
-10
4
NY
YN
YN
YN
3
2

【样例输出】

5

【数据规模与约定】
  对于100%的数据, 满足1 ≤N, M ≤ 50。

Solution:

Other:

  据说是最简单的组合数呢。

  考场玩了一个多小时也没证明出来。

  所以留坑...?

 

  1 #include 
  2 #include 
  3 #include <string>
  4 #include 
  5 #include 
  6 #include <set>
  7 #include 
  8 #include 
  9 #include 
 10 #include 
 11 #include 
 12 #include 
 13 #include 
 14 #include 
 15 #include 
 16 #include 
 17 
 18 using namespace std;
 19 
 20 #define MAXM 60
 21 #define MAXN 60
 22 
 23 #define DEBUG 0
 24 
 25 typedef long int  LINT;
 26 typedef long long INT64;
 27 
 28 typedef struct stProblem {
 29     int score;
 30     int state;
 31 } tProblem;
 32 tProblem problem[MAXM];
 33 
 34 typedef struct stOIer {
 35     int  id;
 36     LINT max;
 37     LINT min;
 38 } tOIer;
 39 tOIer oier[MAXN];
 40 
 41 int  p[MAXN];
 42 
 43 int  n, m, s, t;
 44 
 45 INT64 ans;
 46 
 47 INT64 calc_c(LINT m, LINT n) {
 48     if ((m < 0) || (n < 0))
 49         return 0;
 50     if (m == 0)
 51         return 1;
 52     if (n == 0)
 53         return 0;
 54     
 55     if (m > n)
 56         return 0;
 57     if (m == n)
 58         return 1;
 59     
 60     INT64 result = 1;
 61     for (int i = 0; i < n - m; ++i) {
 62         result = result * (n - i) / (1 + i);
 63     }
 64     
 65     return result;
 66 }
 67 
 68 void bubble_sort() {
 69     int bubble_sort_cmp(tOIer *a, tOIer *b);
 70     
 71     for (int i = 0; i < n - 1; ++i)
 72         for(int j = n - 1; j > i; --j)
 73             if (bubble_sort_cmp(oier + (j - 1), oier + j) < 0)
 74                 swap(oier[j - 1], oier[j]); // Defined in algorithm.h.
 75 }
 76 
 77 int bubble_sort_cmp(tOIer *a, tOIer *b) {
 78     if (a->max < b->max) {
 79         return -1;
 80     } else if (a->max == b->max) {
 81         return 0; 
 82         if (a->id > b->id)
 83             return -1;
 84         else
 85             return 1;
 86     } else { 
 87         return 1;
 88     }
 89 }
 90 
 91 int main(int argc, char *argv[]) {
 92     scanf("%d\n", & m);
 93     
 94     LINT temp_score;
 95     for (int i = 0; i < m; ++i) {
 96         scanf("%ld\n", & temp_score);
 97         if (temp_score > 0) {
 98             problem[i].score = temp_score;
 99             problem[i].state = 1;
100         } else {
101             problem[i].score = -temp_score;
102             problem[i].state = 0;
103         }
104     }
105     
106     scanf("%d\n", & n);
107     
108     char temp_state[MAXM];
109     for (int i = 0; i < n; ++i) {
110         oier[i].id = i;
111         
112         scanf("%s\n", temp_state);
113         for (int j = 0; j < m; ++j)
114             if (problem[j].state) {
115                 if ('Y' == temp_state[j]) {
116                     oier[i].max += problem[j].score;
117                     oier[i].min += problem[j].score;
118                 }
119             } else {
120                 if ('Y' == temp_state[j])
121                     oier[i].max += problem[j].score;
122             }
123     }
124     
125     scanf("%d\n", & s);
126     scanf("%d\n", & t);
127 
128     bubble_sort(); // Max Score DESC Id ASC.
129 
130     for (int i = 0; i < n; ++i)
131         for (int j = 0; j < i;
132             p[i] += ((oier[j].min > oier[i].max)
133                     || ((oier[j].min == oier[i].max) && (oier[j].id < oier[i].id))), ++j)
134             ;
135     
136     #if DEBUG
137         for (int i = 0; i < n; ++i)
138             printf("%d(ID %d) : MAX(%d), MIN(%d) P(%d)\n", i,
139                     oier[i].id, oier[i].max, oier[i].min, p[i]);
140         printf("\n");
141     #endif
142     
143     int k_min, k_max;
144     ans = 0;
145     for (int i = t - 1; i < n; ++i) {
146         if (p[i] > s - 1)
147            break;
148         
149         k_min = max(p[i] - s + t, 0);
150         k_max = min(p[i], t - 1); // t - 1 - k >= 0
151         
152         #if DEBUG
153             printf("STATE %d, MIN(%d), MAX(%d)\n", i, k_min, k_max);
154         #endif
155         
156         for (int k = k_min; k <= k_max; ++k)
157             ans += calc_c(k, p[i]) * calc_c(t - 1 - k, i - p[i]);
158     }
159     
160     printf("%lld\n", ans);
161 }

//std画风有点神奇我也不太懂...留坑等待更新自己der

 

history

【问题描述】

  zhx 不喜欢研究历史,但是 dhh 是历史大师。

【问题描述】  

  历史学家dhh正在研究一个奇怪的王国的历史。当前阶段的任务是研究该国的交通。

  根据这个奇怪的王国的史书记载,史书开始记载前这个王国有n个城市(城市从0开始标号),但所有城市之间都没有道路相连。

  每一年,在位的国王会修建一条双向道路x<->y(x!=y),一条道路可能被修建多次。

  而在这之间,国王会计划进行若干次旅行。对于计划进行的一次旅行st->ed,如果当时能完成这次旅行,而t年前不能完成这次旅行,那么国王会对之前的建设成果感到满意,否则他会很生气,并在他感到满意之前(包括使他满意的那次旅行)都让史官记录下错误的信息,怎么样得到正确信息将在输入格式中描述。

  当然在这些年中也发生了若干次国王的交替,而每个国王的c值不一定相同,但在国王在位期间c值不会改变(初始国王的c值为0,其他的c值可通过记载得到),新上位的国王开始处于不生气的状态。

  请根据史书帮助DHH得出国王每次对于计划旅行是否满意,从而使DHH能够研究该国的交通。

【输入格式】

  输入多组数据,到EOF结束。
  每组数据第一行两个整数n,m,表示初始城市数和史书记载的内容数。
  接下来m行,每行是以下三种格式之一:
  1.K v,表示国王交替,如果被替换的国王是生气的(即这个是错误信息),那么新国王的c值为 v+被替换的国王的值,否则新国王的c值为v。
  2.R x y,表示史书上记载的是国王修建了x<->y的道路,如果这是错误信息,那么真实信息为 (x+c)%n <-> (y+c)% n的道路。
  3.T st ed t,表示国王计划进行的一次st->ed的旅行,且比较的是t年前的情况(国王可能会和史书开始记载以前的情况比较),如果这是错误信息,那么真实信息为国王计划进行的一次 (st+c)%n -> (ed+c)%n 的旅行,且比较的是(t+c)%n年前的情况。
  注意只有遇到R操作才会使年份的计数+1。

【输出格式】

  每组数据对于每个T的记录输出一行,如果此次计划旅行令国王满意,则输出Y,否则输出N。样

【样例输入】

3 7
R 0 1
T 0 1 1
K 1
R 0 1
T 0 1 1
R 0 1
T 1 2 0

【样例输出】

  Y N Y


【数据规模与约定】
  n,m ≤ 3 × 10^5 , 0 ≤ v,x,y,st,ed < n , 0 ≤ t < m,数据组数≤ 10

 

Solution:

// blog坑填不完了。。。先贴std,不然空着好像不太好

 1 #include 
 2 #include 
 3 #include 
 4 
 5 using namespace std;
 6 
 7 #define rep(i, n) for (int i = 0; i < n; ++i)
 8 
 9 const int MaxN = 300005;
10 
11 int f[MaxN], g[MaxN], h[MaxN];
12 int n, m;
13 long long c;
14 bool ans;
15 char opr[50000];
16 
17 int get(int x, int t) {
18     while (f[x] >= 0 && g[x] <= t) x = f[x];
19     return x;
20 }
21 
22 void merge(int x, int y, int t) {
23     x = get(x, t);
24     y = get(y, t);
25     if (x != y) {
26         if (h[x] > h[y]) swap(x, y);
27         f[x] = y, g[x] = t;
28         h[y] += (h[x] == h[y]);
29     }
30 }
31 
32 int main(void) {    
33     freopen("history.in","r",stdin);
34     freopen("history.out","w",stdout);
35     int t, x, y, z, v;
36 
37     while (scanf("%d%d", &n, &m) != EOF) {
38         rep(i, n) h[i] = 1, f[i] = -1;
39         t = c = ans = 0;
40         while (m--) {
41             scanf("\n%s", opr);
42             if (*opr == 'K')
43                 scanf("%d", &v), c = c * ans + v, ans = 0;
44             else {
45                 scanf("%d%d", &x, &y);
46                 x = (c * ans + x) % n;
47                 y = (c * ans + y) % n;
48 
49                 if (*opr == 'R') {
50                     merge(x, y, ++t);
51                 } else {
52                     scanf("%d", &z);
53                     z = (c * ans + z) % n;
54                     ans = ((get(x, t) == get(y, t)) == (get(x, t - z) == get(y, t - z)));
55                     printf("%c\n", ans ? 'N' : 'Y');
56                 }
57             }
58         }
59     }
60 
61     return 0;
62 }

 

 

转载于:https://www.cnblogs.com/drizzly/p/7641855.html

你可能感兴趣的:(数据结构与算法,面试)