2022阿里笔试编程题ak口糊(4月15日)

写代码20分钟ak,但前面选择题基本全忘了(((

\(A\):签到

\(B\):对每个非'.'位置下、右、右斜上、右斜下方向分别去check4个是否相同即可

\(C\):n<=2000,考虑类似树形背包的转移:

  • 对于每个点,其子树之间必没有父子关系,求每个点所有子树之间的答案取min就是最终答案
  • 每个点所有节点的值组成一个集合,这个集合是可以dfs去dp的

\(a_i<=1000(应该是?), n<=2000\),开数组去存集合不太行,并且求答案需要比较快速。所以对于每个点,开了个set放入已经check完的所有子树,把没check的子树中的点\(x\)在这个set里lower_bound拿到相对近的值的指针,再prev一下,拿到这两个值(如果存在)与x做差取绝对值然后对ans取min,最后按子树顺序把子树插入到check完了的集合里面。(写的好抽象,看代码即可)

#include<bits/stdc++.h>
using namespace std;
#define ll long long

int v[2005];
vector<int>G[2005];

int ans = 1e9;

set<int> dfs(int from, int fa) {
    set<int>now;
    for (auto& to : G[from]) {
        if (to == fa)continue;
        auto tmp = dfs(to, from);
        v[from] += v[to];
        for (auto i : tmp) {
            auto p = now.lower_bound(i);
            if (p != now.end()) {
                ans = min(ans, abs(*p - i));
            }
            if (p != now.begin()) {
                ans = min(ans, abs(*prev(p) - i));
            }
        }
        for (auto i : tmp)
            now.insert(i);
    }
    now.insert(v[from]);
    return now;
}

int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> v[i];
    }
    for (int i = 1; i < n; i++) {
        int x, y;
        cin >> x >> y;
        G[x].push_back(y);
        G[y].push_back(x);
    }
    dfs(1, 0);
    cout << ans;
    return 0;
}

总结:暴力即可

posted @ 2022-04-15 20:33  Lecoww  阅读(225)  评论(0编辑  收藏  举报