ABC394 A ~ F
ABC394
感觉这场 ABC 蛮简单的啊,我这么菜都场切了 \(A\sim F\)
A
int main() {
string s; cin >> s;
for (int i = 0; i < s.size(); i ++)
if (s[i] == '2') cout << 2;
return 0;
}
B
const int N = 60;
string s[N];
int n;
int main() {
cin >> n;
for (int i = 1; i <= n; i ++) cin >> s[i];
sort(s + 1, s + 1 + n, [&](string a, string b) {
return a.size() < b.size();
});
for (int i = 1; i <= n; i ++) cout << s[i];
return 0;
}
C
注意不要看错题
int main() {
string s; cin >> s;
for (int i = s.size() - 1; i >= 1; i --)
if (s[i] == 'A' && s[i - 1] == 'W')
s[i] = 'C', s[i - 1] = 'A';
cout << s << endl;
return 0;
}
D
就是一个判断括号序列是否合法的题,使用栈进行匹配即可。
stack<char> stk;
string s;
int main() {
cin >> s;
map<char, char> h;
h[']'] = '[', h['>'] = '<', h[')'] = '(';
for (int i = 0; i < s.size(); i ++) {
if (s[i] == '(' || s[i] == '<' || s[i] == '[') stk.push(s[i]);
else {
if (stk.empty() || stk.top() != h[s[i]]) {
puts("No");
return 0;
} else stk.pop();
}
}
if (!stk.empty()) puts("No");
else puts("Yes");
return 0;
}
E
注意到 \(N \leq 100\),考虑暴力广搜。
由于我们需要找回文串,所以考虑确定一个回文中心然后暴力向两边拓展相同的字符。
然后你要注意都是单向边,所以你往外拓展的时候要注意边的方向,并且注意不要重复算,不然时间就爆了。
时间复杂度是 \(O(n^4)\) 的,但实际上跑不到这么高,而且 \(AT\) 时间开 2s 不卡常。
const int N = 110;
int n, d[N][N];
char g[N][N];
void bfs(int x, int y) {
queue<PII> q;
q.push({x, y});
if (x == y) d[x][y] = 0;
else d[x][y] = 1;
while (q.size()) {
auto t = q.front(); q.pop();
int a = t.first, b = t.second;
for (int i = 1; i <= n; i ++)
if (g[i][a] != '-')
for (int j = 1; j <= n; j ++)
if (g[b][j] != '-' && g[i][a] == g[b][j]) {
if (d[a][b] + 2 < d[i][j]) {
d[i][j] = d[a][b] + 2;
q.push({i, j});
}
}
}
}
int main() {
n = read();
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
cin >> g[i][j];
memset(d, 0x3f, sizeof d);
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= n; j ++)
if (i == j || g[i][j] != '-')
bfs(i, j);
for (int i = 1; i <= n; i ++, puts(""))
for (int j = 1; j <= n; j ++)
printf("%d ", d[i][j] == INF ? -1 : d[i][j]);
return 0;
}
F
考虑树形 \(DP\)。
先不考虑至少有一个顶点的度数为 \(4\) 这个要求,剩余的条件显然是很好数位 \(DP\) 的。
设 \(ans\) 为全局答案,\(f[u]\) 表示就是祖先所构成的树的一个以 \(u\) 为树根的子树的最大顶点数。那么转移分为两种情况,一种是 \(u\) 的度数为 \(1\),那由于 \(u\) 还有一个父亲连着它,所以 \(u\) 的最大顶点数就是 \(1\);另一种当 \(u\) 的度数为 \(4\) 时,就找 \(u\) 的儿子中 \(f\) 值前三大的 \(f[u_1] + f[u_2] + f[u_3] + 1\)。
然后还要更新全局答案。\(ans\) 就应该用以 \(u\) 为根的子树的最大顶点数更新,度数为 \(4\) 时找出前四大的 \(f[u_1] + f[u_2] + f[u_3] + f[u_4] + 1\) ,\(ans\) 的度数为 \(1\) 时,那就找出最大的 \(f[u_1] + 1\)。
注意这里 \(ans\) 计算的是以 \(u\) 为整棵树根,而不是 \(u\) 为子树根。
最后我要忘记还有一个顶点度数为 \(4\) 的要求,所以最后找出的答案至少要有 \(5\) 个及以上的结点。
const int N = 200010;
int n, a[N], b[N];
int f[N], ans;
int h[N], ne[N << 1], e[N << 1], idx;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
void dp(int u, int fa) {
vector<int> sons;
f[u] = 1;
for (int i = h[u]; ~i; i = ne[i]) {
int j = e[i];
if (j == fa) continue;
dp(j, u);
sons.push_back(f[j]);
}
sort(sons.begin(), sons.end(), [&](int a, int b) {
return a > b;
});
if (sons.size()) ans = max(ans, sons[0] + 1);
if (sons.size() >= 3) f[u] = max(f[u], sons[0] + sons[1] + sons[2] + 1);
if (sons.size() >= 4) ans = max(ans, sons[0] + sons[1] + sons[2] + sons[3] + 1);
}
int main() {
n = read();
memset(h, -1, sizeof h);
for (int i = 1; i < n; i ++) {
int a = read(), b = read();
add(a, b); add(b, a);
}
dp(1, -1);
printf("%d\n", ans <= 4 ? -1 : ans);
return 0;
}
G
待补