KAJIMA CORPORATION CONTEST 2025 (AtCoder Beginner Contest 394)


A - 22222

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int cnt = std::count(s.begin(), s.end(), '2');
    std::cout << std::string(cnt, '2') << "\n";
}

B - cat

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::string> s(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> s[i];
    }

    std::sort(s.begin(), s.end(), [&](std::string & a, std::string & b) {
    	return a.size() < b.size();
    });

    for (auto & x : s) {
    	std::cout << x;
    }
    std::cout << "\n";
}

C - Debug

题意:给你一个字符串,把WA都改成AC

从后往前做。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    for (int i = n - 1; i ; -- i) {
    	if (s[i - 1] == 'W' && s[i] == 'A') {
    		s[i - 1] = 'A'; s[i] = 'C';
    	}
    }

    std::cout << s << "\n";
}

D - Colorful Bracket Sequence

题意:有三种括号,问这个序列是否是合法的括号序列。

用栈存左括号,每次遇到右括号看栈顶的括号能不能和它匹配就行。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    std::map<char, char> mp;
    mp['['] = ']';
    mp['('] = ')';
    mp['<'] = '>';

    std::stack<char> stk;
    for (auto & c : s) {
    	if (mp.count(c)) {
    		stk.push(c);
    	} else if (stk.empty() || mp[stk.top()] != c) {
    		std::cout << "No\n";
    		return;
    	} else {
    		stk.pop();
    	}
    }

    if (stk.size()) {
    	std::cout << "No\n";
    	return;
    }

    std::cout << "Yes\n";
}

E - Palindromic Shortest Path

题意:给你一个邻接矩阵,权值为一个小写字母,求每个i,j的路径是回文串的最短路是多少。

建立一个正向图和一个反向图,把d[i][i]=0d[i][j]=1,s[i][j]!=入队,那么d[i][j]表示从ij的回文路径最短距离,那么它们两个一个往反图扩展,一个往正图扩展就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::string> s(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> s[i];
    }

    std::vector<std::array<std::vector<int>, 26>> adj1(n), adj2(n);
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		if (s[i][j] != '-') {
    			adj1[i][s[i][j] - 'a'].push_back(j);
    			adj2[j][s[i][j] - 'a'].push_back(i);
    		}
    	}
    }

    std::vector d(n, std::vector<int>(n, -1));
    std::queue<std::pair<int, int>> q;
    for (int i = 0; i < n; ++ i) {
    	d[i][i] = 0;
    	q.push({i, i});
    }

    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		if (i == j) {
    			continue;
    		}
    		if (s[i][j] != '-') {
    			d[i][j] = 1;
    			q.push({i, j});
    		}
    	}
    }

    while (q.size()) {
    	auto [u, v] = q.front(); q.pop();
    	for (int i = 0; i < 26; ++ i) {
    		for (auto & x : adj2[u][i]) {
    			for (auto & y : adj1[v][i]) {
    				if (d[x][y] == -1) {
    					d[x][y] = d[u][v] + 2;
    					q.push({x, y});
    				}
    			}
    		}
    	}
    }

    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < n; ++ j) {
    		std::cout << d[i][j] << " \n"[j == n - 1];
    	}
    }
}

F - Alkane

题意:给你一棵树,要求满足每个点度数要么是1要么是4且最少有一个度数是4的节点的子图中节点数最多的。

考虑树形dp,记f[u]表示以u为根的子树的最大值,那么初始f[u]=1,然后u需要选至少三个子节点,然后加上一个父节点就可以满足要求,那么选f值最大的三个子节点就行,如果子节点有四个以上,则可以直接拿最大的四个更新答案,但不要更新f[u]。然后如果有至少三个节点,那么拿三个最大的子节点加一个父节点更新答案。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<std::vector<int>> adj(n);
    for (int i = 1; i < n; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	-- u, -- v;
    	adj[u].push_back(v);
    	adj[v].push_back(u);
    }

    std::vector<int> f(n);
    int ans = 0;
    auto dfs = [&](auto self, int u, int fa) -> void {
    	f[u] = 1;
    	std::vector<int> a;
    	for (auto & v : adj[u]) {
    		if (v == fa) {
    			continue;
    		}

    		self(self, v, u);

    		a.push_back(f[v]);
    	}

    	std::sort(a.begin(), a.end(), std::greater<int>());

    	if (a.size() >= 3) {
    		f[u] = std::max(f[u], a[0] + a[1] + a[2] + 1);
    		if (a.size() >= 4) {
    			ans = std::max(ans, a[0] + a[1] + a[2] + a[3] + 1);
    		}

    		if (u != 0) {
    			ans = std::max(ans, f[u] + 1);
    		}
    	}
    };

    dfs(dfs, 0, -1);

    if (ans == 0) {
    	ans = -1;
    }
    std::cout << ans << "\n";
}

G - Dense Buildings

题意:有一个n×m的矩阵,其中h[i][j]表示(i,j)的层数,你可以在任意相邻的两栋楼的同一层直接移动,不消耗代价。如果你在任意一栋楼向上或向下一层,都要付出1的代价。你到(i,j)时楼层数不能大于h[i][j],每次求从(a,b)的第x层到(c,d)的第y层的最小代价。

显然在移动过程中,会先下降到一个最低点,然后上升到目标楼层。那么如果我们知道了这个最低点,就可以一开始直接下到这个点,然后就可以沿着这条路径上的楼一直到目标楼,然后再上到目标楼层,代价是xmin+ymin。那么我们要求的就是使得min最大。
那么我们可以建图,(i,j)向四周建min(h[i][j],h[i+dx][j+dy])的边,意味想要从(i,j)(i+dx,j+dy)楼层不能高于min(h[i][j],h[i+dx][j+dy])。然后我们求最大生成树,那么最大生成树上的路径就是最优路径,因为瓶颈边都在最大生成树上。那么就变成了求树上两个点路径边权最小值的问题,通过lca可以求出。

点击查看代码
struct DSU {
	std::vector<int> fa, cnt;
	DSU(int _n) {
		init(_n);
	}

	void init(int _n) {
		fa.assign(_n, 0);
		cnt.assign(_n, 1);
		std::iota(fa.begin(), fa.end(), 0);
	}

	int find(int x) {
		return x == fa[x] ? x : fa[x] = find(fa[x]);
	}

	bool merge(int x, int y) {
		x = find(x), y = find(y);
		if (x == y) {
			return false;
		}

		fa[y] = x;
		cnt[x] += cnt[y];
		return true;
	}

	bool same(int x, int y) {
		return find(x) == find(y);
	}

	int size(int x) {
		return cnt[find(x)];
	}
};

void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector h(n, std::vector<int>(m));
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < m; ++ j) {
    		std::cin >> h[i][j];
    	}
    }

    auto get = [&](int x, int y) -> int {
    	return x * m + y;
    };

    std::vector<std::array<int, 3>> edges;
    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < m; ++ j) {
    		if (i + 1 < n) {
    			edges.push_back({std::min(h[i][j], h[i + 1][j]), get(i, j), get(i + 1, j)});
    		}

    		if (j + 1 < m) {
    			edges.push_back({std::min(h[i][j], h[i][j + 1]), get(i, j), get(i, j + 1)});
    		}
    	}
    }

    std::sort(edges.begin(), edges.end(), std::greater<>());
    std::vector<std::vector<std::pair<int, int>>> adj(n * m);
    DSU dsu(n * m);
    for (auto & [w, u, v] : edges) {
    	if (dsu.same(u, v)) {
    		continue;
    	}

    	dsu.merge(u, v);
    	adj[u].push_back({v, w});
    	adj[v].push_back({u, w});
    }

    const int lg = std::__lg(n * m) + 1, inf = 2e9;
    std::vector f(n * m, std::vector<int>(lg + 1));
    std::vector min(n * m, std::vector<int>(lg + 1, inf));
    std::vector<int> d(n * m);
    std::queue<int> q;
    q.push(0);
    d[0] = 1;
    while (q.size()) {
    	int u = q.front(); q.pop();
    	for (auto & [v, w] : adj[u]) {
    		if (d[v] == 0) {
    			d[v] = d[u] + 1;
    			f[v][0] = u;
    			min[v][0] = w;
    			for (int j = 1; j <= lg; ++ j) {
    				f[v][j] = f[f[v][j - 1]][j - 1];
    				min[v][j] = std::min(min[v][j - 1], min[f[v][j - 1]][j - 1]);
    			}
    			q.push(v);
    		}
    	}
    }

    auto lca = [&](int x, int y) -> int {
    	if (d[x] < d[y]) {
    		std::swap(x, y);
    	}

    	int res = inf;
    	for (int i = lg; i >= 0; -- i) {
    		if (d[f[x][i]] >= d[y]) {
    			res = std::min(res, min[x][i]);
    			x = f[x][i];
    		}
    	}

    	if (x == y) {
    		return res;
    	}

    	for (int i = lg; i >= 0; -- i) {
    		if (f[x][i] != f[y][i]) {
    			res = std::min({res, min[x][i], min[y][i]});
    			x = f[x][i];
    			y = f[y][i];
    		}
    	}

    	res = std::min({res, min[x][0], min[y][0]});
    	return res;
    };

    int Q;
    std::cin >> Q;
    while (Q -- ) {
    	int a, b, x, c, d, y;
    	std::cin >> a >> b >> x >> c >> d >> y;
    	-- a, -- b, -- c, -- d;
    	int u = get(a, b), v = get(c, d);
    	if (u == v) {
    		std::cout << std::abs(x - y) << "\n";
    		continue;
    	}

    	int min = std::min({x, y, lca(u, v)});
    	std::cout << x + y - 2 * min << "\n";
    }
}
posted @   maburb  阅读(103)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示