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 }