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

待补

posted @ 2025-02-23 11:04  はなこくん  阅读(21)  评论(0)    收藏  举报