AIM Tech Round 3 (Div. 2) (B C D E) (codeforces 709B 709C 709D 709E)
rating又掉下去了。好不容易蓝了。。。。
A。。没读懂题,wa了好几次,明天问队友补上。。。
题意:一条直线上n个点x1,x2...xn,现在在位置a,求要经过任意n-1个点的最小路程
题解:分类讨论,乱搞搞总会出来的,我大概写的很笨……
#include <bits/stdc++.h> using namespace std; typedef long long ll; int x[100005]; ll cal(ll x, ll a, ll z) { return min((a-x)*2+(z-a) , (z-a)*2+(a-x)); } int main() { int n, a; scanf("%d%d", &n, &a); for (int i = 0; i < n; ++i) { scanf("%d", x+i); } sort(x, x+n); ll ans = 1e18, tmp; if (n == 1) cout << 0; else if (n == 2) cout << min(abs(a-x[0]), abs(a-x[1])); else if (a >= x[n-1]) cout << a-x[1]; else if (a <= x[0]) cout << x[n-2]-a; else if (a <= x[1]) cout << min(cal(x[0], a, x[n-2]), (ll)(x[n-1]-a)); else if (a > x[n-2]) cout << min(cal(x[1], a, x[n-1]), (ll)(a-x[0])); else cout << min(cal(x[0],a,x[n-2]), cal(x[1],a,x[n-1])); return 0; }
题意:给一个字符串,要求替换任意一个非空字串,使得替换后字串字典序最小。替换的方法是z->y,y->x,....,b->a,a->z
题解:C题怎么会这么简单。。。很容易想到替换尽可能靠前的字符,而且不能替换a,注意题目要求的必须替换一个字串,所以字串中所有字母都是a的时候,只能把最后一个变成z了。
#include <bits/stdc++.h> using namespace std; typedef long long ll; char a[100005]; int main() { while (cin >> a) { bool fg = false; int n = strlen(a); int cnt = 0; for (int i = 0; i < n; ++i) { if (a[i] != 'a') {a[i]--; fg=true;} else if(fg) break; } if (!fg) a[n-1] = 'z'; cout << a << endl; } return 0; }
题意:对于一个只有0和1的序列,会有很多00,01,10,11的子序列,现在给你00,01,10,11的子序列的数量,求符合要求的子串,没有输出Impossible
题解:注意,子序列不同于子串,不连续。
设子串中0的数量是x,那么00的数量一定是C(2,x),1同理。然后设0的数量是x,1的数量是y,所以所有子序列的个数是C(2,x+y),即C(2,x+y)==a+b+c+d,如果不相等则不可能构成。要注意的地方是当00的数量为0的时候,x既可以为0,也可以为1,需要根据bc判断。y同理。
至于字符串的构造,有点贪心的想法。瞎搞的。。。。
#include <bits/stdc++.h> using namespace std; typedef long long ll; char ans[1000005]; int main() { ll a, b, c, d; while (cin >> a >> b >> c >> d) { ll x = (ll)sqrt(a*2)+1; ll y = (ll)sqrt(d*2)+1; if (a+b+c+d == 0) { puts("0"); continue; } if (a == 0) { if (b || c) x = 1; else x = 0; } if (d == 0) { if (b || c) y = 1; else y = 0; } if (!(x*(x-1) == a*2 && y*(y-1) == d*2)) { puts("Impossible"); continue; } ll n = x+y; ll xnt = n*(n-1)/2-a-d; if (b+c != xnt) { puts("Impossible"); continue; } int idx = 0; int cnt = x+y; while (cnt) { if (b < y) { ans[idx++] = '1'; c -= x; y--; } else if (c < x) { ans[idx++] = '0'; b -= y; x--; } else if (b >= c) { ans[idx++] = '0'; b -= y; x--; } else { ans[idx++] = '1'; c -= x; y--; } cnt--; } ans[idx] = 0; printf("%s\n", ans); } return 0; }
题意:给一棵树,对于每一个结点,可不可以通过在树上去掉一条边再增加一条边(必须还是一棵树),使这个结点成为这棵树的重心。
题解:%%%明神
对于一个点,如果不能当重心,一定是它有一棵子树u,size[u]>n/2,那么只要在这个子树u中找到一个子树v,满足size[v]<=n/2且size[u]-size[v]<=n/2就可以了。
于是树形dp,求每个点的<=n/2的最大子树的大小。
至于向上思想类似,随便搞搞,具体看代码。
不喜欢用邻接表存图,看起来很麻烦,可是vector确实会慢一些,比赛一定不能用=。=
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 400005; vector<int> g[N]; int sz[N], up[N], dn[N]; // up向上的最大的不大于n/2的子树大小 dn向下的 int ans[N]; int n; inline int read() { char ch = getchar(); int data = 0; while (ch < '0' || ch > '9') ch = getchar(); do { data = data*10 + ch-'0'; ch = getchar(); } while (ch >= '0' && ch <= '9'); return data; } void UP(int &x, int y) { if(y>x) x=y; } void dfs(int u, int fa) { // 第一遍向下dfs sz[u] = 1; for (int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if (v == fa) continue; dfs(v, u); if (sz[v] - dn[v] > n/2) ans[u] = 0; sz[u] += sz[v]; UP(dn[u], dn[v]); } if (sz[u] <= n/2) dn[u] = sz[u]; } void dfs1(int u, int fa) { // 第二遍向上 if (n-sz[u] - up[u] > n/2) ans[u] = 0; if (n-sz[u] <= n/2) up[u] = n-sz[u]; int mx = 0; // 对于每一个结点向上的最大值 可能来自向上的链 也可能来自父节点的其他子树 // mx记录的就父节点其他子树的最大值 for (int i = 0; i < g[u].size(); ++i) { int v = g[u][i]; if (v == fa) continue; up[v] = max(up[u], mx); UP(mx, dn[v]); } mx = 0; for (int i = g[u].size()-1; i >= 0; --i) { int v = g[u][i]; if (v == fa) continue; UP(up[v], mx); UP(mx, dn[v]); dfs1(v, u); } } int main() { scanf("%d", &n); int u, v; for (int i = 1; i < n; ++i) { u = read(); v = read(); g[u].push_back(v); g[v].push_back(u); } if (n == 2) { printf("1 1"); return 0; } for (int i = 1; i <= n; ++i) ans[i] = 1; dfs(1, 0); dfs1(1, 0); for (int i = 1; i <= n; ++i) { printf("%d", ans[i]); if (i != n) printf(" "); } return 0; }