当前位置: 首页 > article >正文

Atcoder Beginner Contest 381

比赛链接:AtCoder Beginner Contest 381 - AtCoder

A - 11/22 String

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

signed main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int n; string s;
	cin >> n >> s;
	if (n & 1) {
		for (int i = 0; i < n / 2; i++) if (s[i] != '1') { cout << "No" << endl; return 0; }
		if (s[n / 2] != '/') { cout << "No" << endl; return 0; }
		for (int i = n / 2 + 1; i < n; i++) if (s[i] != '2') { cout << "No" << endl; return 0; }
		cout << "Yes" << endl;
		return 0;
	}
	cout << "No" << endl;
    return 0;
}

B - 1122 String

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

signed main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int n; string s;
	cin >> s;
	n = s.size();
	map<char, int> mp;
	if (n & 1) { cout << "No" << endl; return 0; }
	for (int i = 1; i < n; i += 2) {
		if (s[i] != s[i - 1]) {
			cout << "No" << endl;
			return 0;
		}
		if (mp.find(s[i]) != mp.end()) {
			cout << "No" << endl;
			return 0;
		}
		mp[s[i]] = 2;
	}
	cout << "Yes" << endl;
    return 0;
}

C - 11/22 Substring

遍历字符串,当当前字符为 '/' 的时候,分别向左边找连续 1,向右边找连续 2 的个数,当前合法的 11/22 串长度为两者最小值的两倍加 1。

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

signed main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int n; string s;
	cin >> n >> s;
	int ans = 0;
	for (int i = 0; i < n; i++) {
		if (s[i] == '/') {
			int l = i, r = i;
			while (l - 1 >= 0 && s[l - 1] == '1') l--;
			while (r + 1 < n && s[r + 1] == '2') r++;
			int res = min(r - i, i - l);
			ans = max(ans, 2 * res + 1);
		}
	}
	cout << ans << endl;
    return 0;
}

D - 1122 Substring

根据题意利用双指针来做。

如果接下来两个数相同,

  • 该数在前面子串没有出现,将右端指针往后移两位。
  • 该数在前面子串已经出现,记录答案,左端指针右移至该数的位置, 再将右端指针往后移两位。
#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int n, a[N];

int main() {
    ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    int l = 1, ans = 0;
    map<int, int> cnt; // 记录数字在连续子串中是否出现
    for (int r = 1; r <= n; r++) {
		if ((r > 1 && a[r] == a[r - 1]) || (r - l) % 2 == 0) {
        	cnt[a[r]]++;
			while (cnt[a[r]] > 2) {
				cnt[a[l]]--;
				if (cnt[a[l]] == 0) cnt.erase(a[l]);
				l++;
			}
			if ((r - l + 1) % 2 == 0) {
				ans = max(ans, r - l + 1);
			}
		}
		else {
			cnt.clear();
			l = r;
			cnt[a[r]] = 1;
		}
    }
    cout << ans << endl;
    return 0;
}

E - 11/22 Subsequence

记录字符串前缀中 1 和 2 的数量以及字符 '/' 的位置。对于每次查询,利用二分找出所有在区间内的 '/' 的下标范围 [ L, R ],再在这个区间内利用二分找到最长的子序列长度。

子序列长度等于 '/' 左侧 1 的数量和右侧 2 的数量的最小值的两倍加 1。

  • 左侧的 1 数量大于右侧 2 的数量时,最长子序列对应的 '/' 在右边。
  • 左侧的 1 数量小于右侧 2 的数量时,最长子序列对应的 '/' 在左边。
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5 + 10;
int n, q, a[N], b[N];
vector<int> v;
string s;

int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n >> q >> s;
	int len = s.size();
	s = " " + s;
	for (int i = 1; i <= len; i++) {
		a[i] = a[i - 1] + (s[i] == '1');
		b[i] = b[i - 1] + (s[i] == '2');
		if (s[i] == '/') v.push_back(i);
	}
	while (q--) {
		int l, r, ans = 0; cin >> l >> r;
		int L = lower_bound(v.begin(), v.end(), l) - v.begin();
		int R = upper_bound(v.begin(), v.end(), r) - v.begin() - 1;
		while (L <= R) {
			int mid = L + R >> 1;
			int c1 = a[v[mid] - 1] - a[l - 1], c2 = b[r] - b[v[mid]];
			ans = max(ans, 2 * min(c1, c2) + 1);
			if (c1 < c2) L = mid + 1;
			else R = mid - 1;
		}
		cout << ans << '\n';
	}
	return 0;
}

F - 1122 Subsequence

状压DP。设 dp_j 为当前子序列状态为 j 的最短前缀长度,j 是一个表示是否包含数字 i 的二进制数 (1\le i\le 20)。对于数字 i,只需要从 j \oplus (1 << (i - 1)) 转移到当前位置即可。

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

int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	int n; cin >> n;
	vector<int> a(n + 1), dp(1 << 20 + 5, INT_MAX);
	vector<vector<int>> pos(21);
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
		pos[a[i]].push_back(i); // 记录 a[i] 出现的位置
	}
	dp[0] = 0;
	int ans = 0;
	for (int j = 1; j < (1 << 20); j++) {
		for (int i = 1; i <= 20; i++) {
            // j 为当前状态,需要判断 j 状态中 i 对应的位置上是否为 1
            // 即 j 状态是否表示已经包含了 i 这个数字
            // 同时还需要判断 j ^ (1 << (i - 1)) 这个状态是否存在
			if ((j & (1 << (i - 1))) && dp[j ^ (1 << (i - 1))] != INT_MAX) {
				int idx = upper_bound(pos[i].begin(), pos[i].end(), dp[j ^ (1 << (i - 1))]) - pos[i].begin();
                // 找出第一个在 dp[j ^ (1 << (i - 1))] 后面的 i 的位置
				if (idx + 1 < pos[i].size()) dp[j] = min(dp[j], pos[i][idx + 1]);
                // 子序列需要插入两个相同的数,所以判断 idx + 1 是否合法
			}
		}
		if (dp[j] != INT_MAX) {
			int res = 0, tmp = j;
			while (tmp) res += (tmp & 1), tmp >>= 1; // 统计 j 的二进制表示中 1 的个数
			ans = max(ans, 2 * res);
		}
	}
	cout << ans << '\n';
	return 0;
}


http://www.kler.cn/a/406866.html

相关文章:

  • 快速图像识别:落叶植物叶片分类
  • LeetCode 746. 使用最小花费爬楼梯 java题解
  • VXLAN说明
  • 时间操作[计算时间差]免费API接口教程
  • ROS机器视觉入门:从基础到人脸识别与目标检测
  • Go语言的并发与管道
  • el-table :span-method 合并单元格(2.0)
  • 整站使用Vue(工程化)
  • C语言练级->##__VA_ARGS__(可变参数)的用法
  • uniapp中使用uni.$emit和uni.$on进行页面通讯传值
  • 3-测试go-redis+redsync实现分布式锁 --开源项目obtain_data测试
  • VRRP实现出口网关设备冗余备份
  • win10中使用ffmpeg和MediaMTX 推流rtsp视频
  • JAVA下载EXCEL,PDF文件之后无法打开,提示文件损坏
  • electron主进程和渲染进程之间的通信
  • 大数据学习18之Spark-SQL
  • STL关联式容器之multiset及multimap
  • Flutter:AnimatedSwitcher当子元素改变时,触发动画
  • Ansible使用简介和基础使用
  • 嵌入式 UI 开发的开源项目推荐
  • C#学习笔记——窗口停靠控件WeifenLuo.WinFormsUI.Docking使用-腾讯云开发者社区-腾讯云
  • vue3中父div设置display flex,2个子div重叠
  • 华为无线AC+AP组网实际应用小结
  • FreeIPCC:Ai智能呼叫中心是什么?
  • 【数据结构】归并排序 —— 递归及非递归解决归并排序
  • 基于自混合干涉测量系统的线展宽因子估计算法matlab仿真