VP AtCoder Beginner Contest 381

A - 11/22 String

题意:定义\(11/22\)串是前面都是\(1\)后面都是\(2\)\(1,2\)的个数相同,中间是一个'/'。 判断给你的字符串是不是\(11/22\)串。

模拟即可。

点击查看代码
void solve() {
	int n;
	std::cin >> n;
    std::string s;
    std::cin >> s;
    if (n % 2 == 0 || s.substr(0, n / 2) != std::string(n / 2, '1') || s.substr(n / 2 + 1) != std::string(n / 2, '2') || s[n / 2] != '/') {
    	std::cout << "No\n";
    } else {
    	std::cout << "Yes\n";
    }
}

B - 1122 String

题意:定义\(1122\)串为每个奇数位置\(i\),都有\(a_i = a_{i+1}\),并且每个数只能恰好出现两次。判断是不是\(1122\)串。

一样模拟。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    int n = s.size();
    if (n & 1) {
    	std::cout << "No\n";
    	return;
    }

    std::vector<int> cnt(26);
    for (int i = 0; i < n; i += 2) {
    	if (s[i] != s[i + 1]) {
    		std::cout << "No\n";
    		return;
    	}

    	if (cnt[s[i] - 'a']) {
    		std::cout << "No\n";
    		return;
    	}

    	cnt[s[i] - 'a'] = 1;
    }

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

C - 11/22 Substring

题意:和\(A\)题一样,不过要你判断字符串是\(11/22\)串的最长子串的长度。

在每个'/'处两边扩展记录最长长度即可。

点击查看代码
void solve() {
	int n;
	std::cin >> n;
	std::string s;
	std::cin >> s;
	int ans = 0;
	for (int i = 0; i < n; ++ i) {
		if (s[i] == '/') {
			int k = 1;
			while (i - k >= 0 && i + k < n && s[i - k] == '1' && s[i + k] == '2') {
				++ k;
			}

			ans = std::max(ans, (k - 1) * 2 + 1);
		}
	}

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

D - 1122 Substring

题意:和\(B\)题一样,不过要你判断字符串是\(1122\)串的最长子串的长度。

记录每个数出现的次数,分奇数起点和偶数起点分别双指针模拟即可。

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

    std::vector<int> st(n + 1);
    int ans = 0;
    for (int i = 0, j = 0; i + 1 < n;) {
    	j = std::max(i, j);
    	while (j + 1 < n && a[j] == a[j + 1] && st[a[j]] == 0) {
    		st[a[j]] = 1;
    		j += 2;
    	}

    	ans = std::max(ans, j - i);
		st[a[i]] = 0;
    	i += 2;
    }

    for (int i = 1, j = 1; i + 1 < n;) {
    	j = std::max(i, j);
    	while (j + 1 < n && a[j] == a[j + 1] && st[a[j]] == 0) {
    		st[a[j]] = 1;
    		j += 2;
    	}

    	ans = std::max(ans, j - i);
		st[a[i]] = 0;
    	i += 2;
    }

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

E - 11/22 Subsequence

题意:和\(A\)一样,不过有\(Q\)次询问,每次问你\([L, R]\)区间内\(11/22\)最长子序列是多少。

把所有'/'的位置存下来,然后记录\(1\)\(2\)的前缀和。那么每次找到第一个位置大于等于\(L\)的'/'和最后一个小于等于\(R\)的'/',那么可以二分,如果当前'/'两边\(1\)的个数大于等于\(2\)的个数我们就应该往左边走,否则往右边走。因为这个二分出来的不一定是最优解,所以我们需要在二分过程中记录答案。

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

	std::vector<int> sum1(n + 1), sum2(n + 1);
	std::vector<int> a;
	for (int i = 0; i < n; ++ i) {
		sum1[i + 1] = sum1[i] + (s[i] == '1');
		sum2[i + 1] = sum2[i] + (s[i] == '2');
		if (s[i] == '/') {
			a.push_back(i + 1);
		}
	}

	while (q -- ) {
		int l, r;
		std::cin >> l >> r;
		int L = std::lower_bound(a.begin(), a.end(), l) - a.begin();
		int R = std::upper_bound(a.begin(), a.end(), r) - a.begin() - 1;
		if (L > R) {
			std::cout << 0 << "\n";
			continue;
		}

		int ans = 0;
		while (L <= R) {
			int mid = L + R >> 1;
			int one = sum1[a[mid]] - sum1[l - 1], two = sum2[r] - sum2[a[mid]];
			ans = std::max(ans, std::min(one, two));
			if (one >= two) {
				R = mid - 1;
			} else {
				L = mid + 1;
			}
		}

		std::cout << ans * 2 + 1 << "\n";
	}
}

F - 1122 Subsequence

题意:跟\(B\)题一样,不过要你求最长的\(1122\)子序列。

注意值域只有\(20\),我们可以状压。记录满足\(f_i\)这个状态用到的数的最后位置。用\(suf_{i,j}\)记录第\(i\)个位置后面\(j\)出现的最早位置。那么如果\(suf_{f_i,j}\)\(suf_{suf_{f_i,j},j}\)都存在,那么\(f_i\)可以转移到\(f_{i|(1<<j)}\)

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

    for (int i = n - 1; i >= 0; -- i) {
    	suf[i] = suf[i + 1];
    	suf[i][a[i]] = i + 1;
    }

    std::vector<int> f(1 << 20, n + 1);
    f[0] = 0;
    for (int i = 0; i < 1 << 20; ++ i) {
    	if (f[i] > n) {
    		continue;
    	}
    	for (int j = 0; j < 20; ++ j) {
    		if ((~i >> j & 1) && suf[f[i]][j] != 0 && suf[suf[f[i]][j]][j] != 0) {
    			f[i | (1 << j)] = std::min(f[i | (1 << j)], suf[suf[f[i]][j]][j]);
    		}
    	}
    }

    int ans = 0;
    for (int i = 0; i < 1 << 20; ++ i) {
    	if (f[i] <= n) {
    		ans = std::max(ans, __builtin_popcount(i));
    	}
    }

    std::cout << ans * 2 << "\n";
}
posted @ 2025-01-19 17:17  maburb  阅读(31)  评论(0)    收藏  举报