2020 HZNU Winter Training Day 9 BC题解

B题

题意:

给一棵树,找到三个顶点,使三个顶点两两之间路径的并集最大

输出:

三个顶点两两之间路径的并集的最大数量,以及这三个点的编号

解析:

用两次BFS可以求出树的直径的两个端点(假设为a,b),在这个过程中还能顺便求出一个端点到树上每一点的距离。

之后再用一次BFS求得另一个端点到树上每一点的距离。

最后枚举点c,满足c到a和c到b的距离和最大。

a,b,c即为所求三点。

最终数量为:[dis(a,b)+dis(b,c)+dis(a,c)]/2

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstring>
 6 #include<queue>
 7 using namespace std;
 8 const int maxn = 200000 + 10;
 9 const int maxm = 400000 + 10;
10 inline int read() {
11     char ch = getchar(); int x = 0, f = 1;
12     while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
13     while ('0' <= ch && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
14     return x * f;
15 }
16 int n, a, b, c, pos;
17 int dis[maxn], dis1[maxn], dis2[maxn], vis[maxn];
18 int head[maxn], ver[maxm], Next[maxm], tot;
19 void add(int u, int v) {
20     ++tot;
21     ver[tot] = v;
22     Next[tot] = head[u];
23     head[u] = tot;
24 }
25 
26 void init() {
27     memset(head, -1, sizeof head);
28     tot = 0;
29 }
30 void bfs(int x) {
31     queue<int>q;
32     memset(vis, false, sizeof vis);
33     memset(dis, 0, sizeof dis);
34     pos = x;
35     vis[x] = 1;
36     dis[x] = 0;
37     q.push(x);
38     while (!q.empty()) {
39         int u = q.front(); q.pop();
40         for (int i = head[u]; i != -1; i = Next[i]) {
41             int y = ver[i];
42             if (!vis[y]) {
43                 vis[y] = 1;
44                 dis[y] = dis[u] + 1;
45                 if (dis[y] > dis[pos])pos = y;
46                 q.push(y);
47             }
48         }
49     }
50 }
51 int main() {
52     init();
53     n = read();
54     for (int i = 1; i < n; ++i) {
55         int x = read(), y = read();
56         add(x, y), add(y, x);
57     }
58     bfs(1); a = pos;
59     bfs(pos); b = pos;
60     //printf("%d %d
", a, b);
61     for (int i = 1; i <= n; ++i)dis1[i] = dis[i];
62     bfs(pos);
63     for (int i = 1; i <= n; ++i)dis2[i] = dis[i];
64     c = 0;
65     for (int i = 1; i <= n; ++i) {
66         if (dis1[i] + dis2[i] > dis1[c] + dis2[c] && i != a && i != b)c = i;
67     }
68     printf("%d
", (dis1[b] + dis1[c] + dis2[c]) / 2);
69     printf("%d %d %d
", a, b, c);
70 }

C题

题意:

给定两个字符串s和t,你有一个空字符串z

每次可以取s的任意一个子序列加到z后面

问至少要取多少次才能让z等价于t

解析:

vector存s字符串中26个字母的位置

然后t字符串从前往后一个个查找

用变量now记录查到上一个字符时在字符串s中的位置(初始化为0)。

如果在t内碰到一个字符,没有在s中出现过,输出-1结束当次程序

否则,看当前的now是否大于等于这个字符在s中出现的最后一个位置,如果是,说明这一次子序列已经不能往后面取了,说明得另起一次从头取子序列,让now等于当前字符在s中出现的第一个位置;如果不是则二分找大于now的第一个这个字符的位置,让now等于这个位置即可。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cstring>
 6 #include<vector>
 7 using namespace std;
 8 #define ll long long
 9 const int inf = 0x3f3f3f3f;
10 const int maxn = 100000 + 10;
11 inline ll read() {
12     char ch = getchar(); ll x = 0, f = 1;
13     while (ch<'0' || ch>'9') { if (ch == '-')f = -1; ch = getchar(); }
14     while ('0' <= ch && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
15     return x * f;
16 }
17 vector<int >v[30];
18 char s[maxn], t[maxn];
19 int main() {
20     int T = read();
21     while (T--) {
22         scanf("%s", s + 1);
23         scanf("%s", t + 1);
24         for (int i = 0; i <= 26; ++i) {
25             v[i].clear();
26         }
27         int slen = strlen(s + 1);
28         bool ok = false;
29         for (int i = 1; i <= slen; ++i) {
30             v[s[i] - 'a'].push_back(i);
31         }
32         int now = 0;
33         int tlen = strlen(t + 1);
34         int res = 0;
35         for (int i = 1; i <= tlen; ++i) {
36             int y = t[i] - 'a';
37             if (v[y].size() == 0) {
38                 ok = true;
39                 break;
40             }
41             int l = 0, r = v[y].size() - 1;
42             int ans = inf;
43             while (l <= r) {
44                 int mid = (l + r) >> 1;
45                 if (v[y][mid] > now) {
46                     ans = v[y][mid];
47                     r = mid - 1;
48                 }
49                 else l = mid + 1;
50             }
51             if (ans == inf)res++, now = v[y][0];
52             else now = ans;
53             //printf("%d
", now);
54         }
55         res++;
56         if (ok)puts("-1");
57         else {
58             printf("%d
", res);
59         }
60     }
61 }
原文地址:https://www.cnblogs.com/JayShao/p/12266935.html