405~407有事情没打所以没写文章

Atcoder ABC408游记(A~E)

A.Timeout

题目描述

beat会立即睡着。具体地说,如果从上次拍打beat的肩膀到现在已过去 S+0.5S+0.5 秒或更长时间,beat就会睡着。

目前,beat是醒着的,一个人刚刚拍了拍beat的肩膀。

从现在开始,这个人会准确地拍打beat的肩膀 NN 次。 ii 次拍肩将在 TiT_i 秒后进行。

判断beat从现在开始到 TNT_N 秒后是否一直保持清醒。

思路

阅读理解题,水

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n, s;
cin >> n >> s;
vector<int> a(n + 1);
a[0] = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
if (a[i] - a[i - 1] > s) {
cout << "No";
return 0;
}
}
cout << "Yes";
}

B.Compression

题目描述

给出长度为 NN 的整数序列 A=(A1,A2,,AN)A=(A_1,A_2,\ldots,A_N)

按升序输出 AA 中包含的数字,去掉重复的数字。

思路

set解决即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
set<int> s;
while (n--) {
int x;
cin >> x;
s.insert(x);
}
cout << s.size() << '\n';
auto it = s.begin();
while (it != s.end()) {
cout << *it << ' ';
it++;
}
return 0;
}

C.Not All Covered

题目描述

beat王国里有NN个城堡,排成一行,编号从11~NN

MM个炮塔,第ii个炮塔可以保护从第lil_i到第rir_i个城堡。

邪恶beat问你最少移除多少个炮塔可以使至少一个城市没有炮塔守护!

思路

差分呀哥们 用线段树和树状数组的走开

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<int> s(n + 2, 0);
for (int i = 0; i < m; i++) {
int l, r;
cin >> l >> r;
s[l] += 1;
if (r + 1 <= n) {
s[r + 1] -= 1;
}
}
int sum = 0;
int ans = 0x3f3f3f3f;
for (int i = 1; i <= n; i++) {
sum += s[i];
if (sum < ans) {
ans = sum;
}
}
cout << ans;
return 0;
}

D.Flip to Gather

题目描述

给你一个长度为 NN 的字符串 SS ,它由 01 组成。

您可以执行以下操作任意次数(可能为零):

  • 选择一个满足 1iN1 \leq i \leq N 的整数 ii ,并将 SiS_i0 改为 1,或从 1 改为 0

你的目标是使 SS 中的 1 最多形成1个区间。求实现目标所需的最少运算次数。

更准确地说,目标是使 SS 中存在一对满足以下两个条件的整数 (l,r)(l,r) 。求实现目标所需的最小运算次数。

  • 1lrN+11 \leq l \leq r \leq N+1 .
  • Si=S_i= 对于满足 1iN1 \leq i \leq N 的每个整数 ii 来说,1lirl \leq i \leq r 是等价的。

可以证明,目标总是可以用有限次的运算来实现。

给出了 TT 个测试用例,请逐一求解。

思路

贪心,我们只保留最长的一段1,其他的删了即可

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<bits/stdc++.h>
using namespace std;
void solve()
{
int n;
string s;
cin >> n >> s;
int cnt1 = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '1') {
cnt1++;
}
}
int maxx = 0;
int cnt2 = 0;
for (int i = 0; i < s.length(); i++) {
int b = (s[i] == '1') ? 1 : -1;
maxx = max(b, maxx + b);
if (maxx > cnt2) {
cnt2 = maxx;
}
}
cout << (cnt1 - cnt2) << '\n';
}
int main()
{
int T;
cin >> T;
while (T--) {
solve();
}
return 0;
}

E.Minimum OR Path

题目描述

给你一个有 NN 个顶点和 MM 条无自循环边的连通无向图,其中顶点的编号从 11NN ,边的编号从 11MM 。边 ii 双向连接顶点 uiu_iviv_i ,其权值为 wiw_i

在从顶点 11 到顶点 NN 的简单路径(不多次访问同一顶点的路径)中,求路径中所有边的权值的 OR\mathrm{OR} 的最小值。

什么是比特 OR\mathrm{OR} 操作?

非负整数 AABB 的位运算 OR\mathrm{OR} , A OR BA\ \mathrm{OR}\ B 的定义如下:

  • 如果二进制表示的 AABB2k2^k 位中至少有一位数字是 11 ,则 A OR BA\ \mathrm{OR}\ B2k2^kk0k \geq 0 )位中的数字是 11 ,否则是 00

例如, 3 OR 5=73\ \mathrm{OR}\ 5 = 7 (二进制表示为: 011 OR 101=111011\ \mathrm{OR}\ 101 = 111 )。
一般来说, kk 非负整数 p1,p2,p3,,pkp_1, p_2, p_3, \dots, p_k 的比特 OR\mathrm{OR} 定义为 (((p1 OR p2) OR p3) OR  OR pk)(\dots ((p_1\ \mathrm{OR}\ p_2)\ \mathrm{OR}\ p_3)\ \mathrm{OR}\ \dots\ \mathrm{OR}\ p_k) ,可以证明这与 p1,p2,p3,pkp_1, p_2, p_3, \dots p_k 的阶数无关。

思路

按位操作即可。

数据范围告诉你wiw_i最大到23012_30 - 1

我们考虑贪心,ansans初始化肯定是所有wiw_iOR\mathrm{OR},然后对于二进制里的第2929到第00位,判断一下如果ansans的这一位可不可以为00

那判断的方法无脑BFS即可,看一下能不能走到NN这个结点就可以了。

我居然会想到dijkstra

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <bits/stdc++.h>
using namespace std;
int n, m;
vector<vector<pair<int, int>>> edges;
bool check(int x)
{
vector<bool> vis(n + 1, 0);
queue<int> q;
q.push(1);
vis[1] = 1;
while (!q.empty()) {
int tp = q.front();
q.pop();
for (int i = 0; i < edges[tp].size(); i++) {
int v = edges[tp][i].first;
int w = edges[tp][i].second;
if ((w & x) != w) {
continue;
}
if (v == n) {
return 1;
}
if (!vis[v]) {
vis[v] = 1;
q.push(v);
}
}
}
return 0;
}

int main()
{
cin >> n >> m;
edges.resize(n + 1);
int cnt = 0;
while (m--) {
int u, v, w;
cin >> u >> v >> w;
edges[u].push_back({v, w});
edges[v].push_back({u, w});
cnt |= w;
}
int ans = cnt;
for (int i = 29; i >= 0; i--) {
if (!(ans & (1 << i))) {
continue;
}
int x = ans & ~(1 << i);
if (check(x)) {
ans = x;
}
}
cout << ans;
return 0;
}