AtCoder Beginner Contest 401


A - Status Code

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    if (n >= 200 && n < 300) {
    	std::cout << "Success\n";
    } else {
    	std::cout << "Failure\n";
    }
}

B - Unauthorized

模拟,用一个变量记录有没有登录。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    int f = 0;
    int ans = 0;
    for (int i = 0; i < n; ++ i) {
    	std::string s;
    	std::cin >> s;
    	if (s == "login") {
    		f = 1;
    	} else if (s == "logout") {
    		f = 0;
    	} else if (s == "public") {

    	} else {
    		ans += !f;
    	}
    }

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

C - K-bonacci

题意:长度为\(n + 1\)的数组,\(i < k\)\(a[i] = 1\),否则\(a[i] = \sum_{j=i-k}^{i-1} a[i]\)。求\(a[n]\)

从前往后枚举,记录前\(k\)个的前缀和就行,算出\(i\),就把第\(i-k\)个从和里减去。

点击查看代码
void solve() {
    int n, k;
    std::cin >> n >> k;
    std::vector<int> a(n + 1);
    const int mod = 1e9;
    i64 sum = 0;
    for (int i = 0; i <= n; ++ i) {
    	if (i < k) {
    		a[i] = 1;
    		sum += 1;
    	} else {
    		a[i] = sum;
    		sum += a[i];
			sum -= a[i - k];
    		sum = (sum % mod + mod) % mod;
    	}
    }

    std::cout << a[n] << "\n";
}

D - Logical Filling

题意:一个只包含'.', 'o', '?'的字符串,通过把'?'变成'.'或者'o'可以变成的字符串里,恰好有\(k\)个'o'且没有两个相邻'o'的所有字符串称为合法字符串,如果一个位置在任意两个不同的合法字符串的取值不同,这个位置是'?',否则就是那个固定的字符。

先把'o'旁边的'?'都变成'.'。那么考虑剩下的'?'怎么填。对于一段连续的'?',设有\(cnt\)个,则最多可以填\(\lceil \frac{cnt}{2} \rceil\)个'o'。那么求出最多可以填多少'o',如果大于等于剩下需要填的'o'的数量,则每个位置都是'?'。否则如果等于剩下需要填的数量,则每个长度为奇数的'?'段是固定的,而长度为偶数的有两种填法。需要特判剩下需要填的'o'是\(0\)个的情况,这个把所有'?'替换为'.'就行。

点击查看代码
void solve() {
    int n, k;
    std::cin >> n >> k;
    std::string s;
    std::cin >> s;

    for (int i = 0; i + 1 < n; ++ i) {
    	if (s[i] == 'o' && s[i + 1] == '?') {
    		s[i + 1] = '.';
    	}

    	if (s[i] == '?' && s[i + 1] == 'o') {
    		s[i] = '.';
    	}
    }	

    int cnto = k - std::ranges::count(s, 'o');
    if (cnto == 0) {
    	for (auto & c : s) {
    		if (c == '?') {
    			c = '.';
    		}
    	}
    	std::cout << s << "\n";
    	return;
    }
    int cnt = 0;
    for (int i = 0; i < n; ++ i) {
    	if (s[i] == '?') {
    		int j = i;
    		while (j < n && s[j] == '?') {
    			++ j;
    		}

			cnt += (j - i + 1) / 2;
    		i = j;
    	}
    }

    if (cnt == cnto) {
    	for (int i = 0; i < n; ++ i) {
	    	if (s[i] == '?') {
	    		int j = i;
	    		while (j < n && s[j] == '?') {
	    			++ j;
	    		}

	    		if (j - i & 1) {
	    			for (int k = i; k < j; ++ k) {
		    			if (k - i & 1) {
		    				s[k] = '.';
		    			} else {
		    				s[k] = 'o';
		    			}
		    		}
		    	}

	    		i = j;
	    	}
	    }
    }

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

E - Reachable Set

题意:给你一个图,对于\(i\)求保留一个恰好包含\([1, i]\)的点的连通块需要删除的最少点。

用并查集维护连通块,每次把一个点和与他相连的点里编号小于它的点合并为一个集合,如果合并完后\([1, n]\)只有一个集合,说明可以构造\([1, n]\)的集合。至于记录需要删去的点,就把前\(i\)个点相连的大于\(i\)的点用\(set\)维护。

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

    std::set<int> s;
    s.insert(0);
    DSU d(n);
    int cnt = 0;
    for (int i = 0; i < n; ++ i) {
		++ cnt;
		for (auto & v : adj[i]) {
			if (v > i) {
				s.insert(v);
			} else {
				cnt -= !d.same(v, i);
				d.merge(v, i);
			}
		}

		while (s.size() && *s.begin() <= i) {
			s.erase(s.begin());
		}

		if (cnt != 1) {
			std::cout << -1 << "\n";
			continue;
		}

    	std::cout << s.size() << "\n";
    }
}

F - Add One Edge 3

待补。

posted @ 2025-04-12 21:58  maburb  阅读(181)  评论(0)    收藏  举报