AtCoder Beginner Contest 404


A - Not Found

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    std::array<int, 26> cnt{};
    for (auto & c : s) {
    	cnt[c - 'a'] = 1;
    }

    for (int i = 0; i < 26; ++ i) {
    	if (!cnt[i]) {
    		std::cout << (char)('a' + i) << "\n";
    		return;
    	}
    }
}

B - Grid Rotation

题意:给你两个\(01\)矩阵\(a, b\),要使得\(a\)变成\(b\)。你每次可以更改\(a\)任意一个位置的值,或者将\(a\)顺时针旋转90度。求最小操作数。

最多旋转三次。那么枚举旋转次数,每个计算最小值。

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

    for (int i = 0; i < n; ++ i) {
    	std::cin >> t[i];
    }

    auto get = [&]() -> int {
    	int res = 0;
    	for (int i = 0; i < n; ++ i) {
    		for (int j = 0; j < n; ++ j) {
    			res += s[i][j] != t[i][j];
    		}
    	}

    	return res;
    };

    int ans = get();
    for (int k = 1; k < 4; ++ k) {
	    auto ns = s;
	    for (int i = 0; i < n; ++ i) {
	    	for (int j = 0; j < n; ++ j) {
	    		ns[j][n - 1 - i] = s[i][j];
	    	}
	    }

	    s = ns;
	    ans = std::min(ans, get() + k);
	}
    std::cout << ans << "\n";
}

C - Cycle Graph?

题意:给你一个图,判断这个图是不是恰好有一个环。

要图联通且边数等于点数且每个点度数都是2才满足条件。

点击查看代码
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<int> in(n);
    DSU dsu(n);
    for (int i = 0; i < m; ++ i) {
    	int u, v;
    	std::cin >> u >> v;
    	-- u, -- v;
    	++ in[u], ++ in[v];
    	dsu.merge(u, v);
    }

    int cnt = 0;
    for (int i = 0; i < n; ++ i) {
    	cnt += dsu.find(i) == i;
    }

    if (n == m && std::ranges::count(in, 2) == n && cnt == 1) {
    	std::cout << "Yes\n";
    } else {
    	std::cout << "No\n";
    }
}

D - Goin' to the Zoo

题意:\(n\)个动物园,\(m\)种动物。每个动物园有一些动物,门票为\(c_i\)。求每个动物看两次以上的最少花费。

显然一个动物园最多看两次,那么每个动物园有3种选择,一共\(3^n\)种方案,暴力枚举计算花费即可。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> c(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> c[i];
    }
    std::vector<std::vector<int>> a(n);
    for (int i = 0; i < m; ++ i) {
    	int k;
    	std::cin >> k;
    	while (k -- ) {
    		int x;
    		std::cin >> x;
    		-- x;
    		a[x].push_back(i);
    	}
    }

    i64 ans = 1e18;
    int tot = std::pow(3, n);
    for (int i = 0; i < tot; ++ i) {
    	i64 sum = 0;
    	std::vector<int> st(m);
    	for (int j = 0, p = 1; j < n; ++ j, p *= 3) {
    		int cnt = i % (p * 3) / p;
    		for (auto & x : a[j]) {
    			st[x] += cnt;
    		}
    		sum += cnt * c[j];
    	}
    	bool flag = true;
    	for (int i = 0; i < m; ++ i) {
    		flag &= st[i] >= 2;
    	}
    	if (flag) {
	    	ans = std::min(ans, sum);
    	}
    }

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

E - Bowls and Beans

题意:有\(n\)个位置\([0, n - 1]\),每个位置可以把自己的豆子给\([i - c_i, i - 1]\)的位置。求最多给几次所有豆子都在\(0\)的位置。

从后往前做,每次应该优先给有豆子且\(i-c_i\)最小的位置。如果都没有豆子,则直接选择\(i-c_i\)最小的。

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

    for (int i = 1; i < n; ++ i) {
    	std::cin >> a[i];
    }

    int ans = 0;
    for (int i = n - 1; i > 0; -- i) {
    	if (!a[i]) {
    		continue;
    	}
    	++ ans;
    	int p = -1;
    	for (int j = c[i]; j < i; ++ j) {
    		if (a[j] && (p == -1 || c[j] < c[p])) {
    			p = j;
    		}
    	}

    	if (p == -1) {
    		for (int j = c[i]; j < i; ++ j) {
	    		if (p == -1 || c[j] < c[p]) {
	    			p = j;
	    		}
	    	}
    	}
    	a[p] += a[i];
    }

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

F - Lost and Pound

待补。


G - Specified Range Sums

题意:一个正整数数组\(a\),满足\(m\)个条件:\(\sum_{i=L_i}^{R_i} a_i = s_i\)。求\(a\)的最小和。

转化为前缀和运算。那么就是\(sum[R_i] - sum[L_i - 1] = s_i\)以及\(sum[i] - sum[i - 1] \geq 1\)。使得\(sum[n]\)最小。
那么可以差分约束。\(sum[R_i] - sum[L_i - 1] = s_i\)可以表示为\(sum[R_i] - sum[L_i - 1] \geq s_i\)以及\(sum[R_i] - sum[L_i - 1] \leq s_i\),那么可以从\(i-1\)\(i\)\(1\)的边,\(L_{i} - 1\)\(R_i\)\(s_i\)的边,\(R_i\)\(L_i - 1\)\(-s_i\)的边。直接跑最长路,如果有正权环则无解。
这题卡\(spfa\),需要用\(bellman\_ ford\)

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<std::vector<std::pair<int, int>>> adj(n + 1);
    auto addEdge = [&](int u, int v, int w) -> void {
    	adj[u].emplace_back(v, w);
    };

    for (int i = 0; i < m; ++ i) {	
    	int l, r, s;
    	std::cin >> l >> r >> s;
    	addEdge(l - 1, r, s);
    	addEdge(r, l - 1, -s);
    }

    for (int i = 1; i <= n; ++ i) {
    	addEdge(i - 1, i, 1);
    }

    const i64 inf = 1e18;
    std::vector<i64> dist(n + 1, -inf);
    dist[0] = 0;
    for (int i = 0; i <= n + 1; ++ i) {
    	bool flag = false;
    	for (int u = 0; u <= n; ++ u) {
    		for (auto & [v, w] : adj[u]) {
    			if (dist[v] < dist[u] + w) {
    				dist[v] = dist[u] + w;
    				flag = true;
    			}
    		}
    	}

    	if (!flag) {
    		break;
    	} else {
    		if (i > n) {
    			std::cout << -1 << "\n";
    			return;
    		}
    	}
    }

    std::cout << dist[n] << "\n";
}
posted @ 2025-05-03 21:40  maburb  阅读(260)  评论(0)    收藏  举报