太爽了

Atcoder ABC393游记(A~F)

比赛链接

A.Poisonous Oyster

题目描述

有四个东西,编号为1 41~4,其中有一个有毒,如果吃了有毒的东西就会挂掉。

第一个人吃了编号为1,21,2的东西,第二个人吃了编号为1,31,3的东西。

现在给你两个字符串S1S_1S2S_2,分别代表两个人的状态,如果是sick表示这个人挂了,如果是fine说明还活着。

问你哪个东西有毒?

思路

没啥好说的

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s1, s2;
cin >> s1 >> s2;
bool c1 = (s1 == "sick"), c2 = (s2 == "sick");
if (c1 && c2) {
cout << 1;
} else if (c1 && !c2) {
cout << 2;
} else if (!c1 && c2) {
cout << 3;
} else {
cout << 4;
}
return 0;
}

B.A…B…C

题目描述

给你一个字符串SS,求有几组(i,j,k)(i,j,k)满足:

  • i<j<ki<j<kSi=S_i=ASj=S_j=BSk=S_k=Cji=kjj-i=k-j

思路

这里NN最大到100100,枚举即可。

代码

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()
{
string s;
cin >> s;
int cnt = 0;
for (int i = 0; i < s.length(); i++) {
for (int j = i + 1; j < s.length(); j++) {
for (int k = j + 1; k < s.length(); k++) {
if (j - i == k - j && s[i] == 'A' && s[j] == 'B' && s[k] == 'C') {
cnt++;
}
}
}
}
cout << cnt;
return 0;
}

C.Make it Simple

题目描述

给你一个NN个点MM条边的无向图,问你最少删除几条边可以使这张图变成简单图?

一个图被称作简单图当且仅当这个图没有重边或自环。

思路

不是,这回abc有点过于简单了吧

我们读入边的时候就可以把答案搞出来,当遇到set中存在的边或者起点和终点相同的时候我们就把答案+1+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
#include<bits/stdc++.h>
using namespace std;
int n, m;
int main()
{
int ans = 0;
cin >> n >> m;
set<pair<int, int>> have;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
if (have.count({u, v}) || have.count({v, u})) {
ans++;
continue;
} else {
have.insert({u, v});
have.insert({v, u});
}
if (u == v) {
ans++;
}
}
cout << ans;
return 0;
}

D.Swap to Gather

题目描述

给你一个NN以及一个长度为NN的01串SS,每次可以交换相邻两个字符的位置。

问你最少进行几次交换可以让所有的1连续?

思路

简单贪心,把所有的1往中间移就是最优方案。

对了,别忘了开ll。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
int n;
string s;
cin >> n >> s;
vector<int> pos;
for (int i = 0; i < s.size(); i++) {
if (s[i] == '1') {
pos.push_back(i);
}
}
int mid = pos.size() / 2;
int m = pos[mid];
int ans = 0;
for (int i = 0; i < pos.size(); i++) {
ans += abs(pos[i] - (m - mid + i));
}
cout << ans;
return 0;
}

E.GCD of Subset

题目描述

给你两个整数NNKK,和一个长度为NN的序列A=(A1,A2,...,AN)A=(A_1,A_2,...,A_N),对于每个1iN1 \leq i \leq N,输出这个问题的解:

  • 当你从AA中选出KK个包含AiA_i的元素,最大可能得到的他们的最大公因数是多少?

思路

我们把cnt[i]cnt[i]定义为因数中有i的数的个数,然后通过这个算答案就行了,具体细节还是要看代码。

代码

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
#include<bits/stdc++.h>
using namespace std;
int main(){
int n, k;
cin >> n >> k;
vector<int> a(n);
int maxx = 0;
for (int i = 0; i < n; i++){
cin >> a[i];
maxx = max(maxx, a[i]);
}
vector<int> tim(maxx + 1, 0);
for (int i = 0; i < n; i++) {
tim[a[i]]++;
}
vector<int> cnt(maxx + 1, 0);
for (int d = 1; d <= maxx; d++){
for (int j = d; j <= maxx; j += d){
cnt[d] += tim[j];
}
}
vector<int> ans(maxx + 1, 0);
for (int d = 1; d <= maxx; d++){
if(cnt[d] >= k){
for (int j = d; j <= maxx; j += d){
ans[j] = max(ans[j], d);
}
}
}
for (int i = 0; i < n; i++){
cout << ans[a[i]] << '\n';
}
return 0;
}

F.Prefix LIS Query

题目描述

给你一个长度为NN的数组A=(A1,A2,,AN)A=(A_1,A_2,\dots,A_N)

回答QQ个问题。第ii个询问是这样的:

给你两个整数RRXX,考虑AA的前RR个元素(A1,A2,,AR)(A_1,A_2,\dots,A_R)的一个子序列(不一定非得连续),满足它严格递增并且元素的最大值X\leq X,输出这个子序列的最大长度。

思路

我们定义dpidp_i为以aia_i结尾的LIS答案。

对于每个位置,用树状数组得到所有比当前的小的数组对应的dpdp的最大值,然后dpidp_i就是这个最大值+1+1

然后我们就可以对于每个询问离线查询就可以搞定了!

upd:这题貌似有二分并且不用数据结构做出来的dalao,太奇妙了。

代码

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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
#include <bits/stdc++.h>
using namespace std;
vector<array<int,3>> tc;
vector<int> vals;
struct node
{
int n;
vector<int> tree;
node(int _n) {
n = _n;
tree.resize(_n + 1, 0);
}
void update(int idx, int val) {
for(; idx <= n; idx += idx & -idx) {
tree[idx] = max(tree[idx], val);
}
}
int query(int idx) {
int res = 0;
for(; idx; idx -= idx & -idx) {
res = max(res, tree[idx]);
}
return res;
}
};
bool cmp(const array<int, 3> &a1, const array<int, 3> &b1)
{
return a1[0] < b1[0];
}
int getidx(int x)
{
return int(lower_bound(vals.begin(), vals.end(), x) - vals.begin()) + 1;
}
int main(){
int n, q;
cin >> n >> q;
vector<int> a(n);
for(int i = 0; i < n; i++){
cin >> a[i];
}
vals = a;
for(int i = 0; i < q; i++){
int r, x;
cin >> r >> x;
vals.push_back(x);
tc.push_back({x, r, i});
}
sort(vals.begin(), vals.end());
vals.erase(unique(vals.begin(), vals.end()), vals.end());
node ndp(vals.size());
vector<int> dp(n, 0);
for(int i = 0; i < n; i++){
int pos = getidx(a[i]);
dp[i] = ndp.query(pos - 1) + 1;
ndp.update(pos, dp[i]);
}
vector<array<int, 3>> info;
for (int i = 0; i < n; i++){
info.push_back({a[i], i + 1, dp[i]});
}
sort(info.begin(), info.end(), cmp);
sort(tc.begin(), tc.end(), cmp);
node nans(n);
vector<int> ans(q, 0);
int cnt = 0;
for(int i = 0; i < tc.size(); i++){
array<int, 3> tp = tc[i];
int x = tp[0], r = tp[1], idx = tp[2];
while(cnt < n && info[cnt][0] <= x) {
int pos = info[cnt][1];
int val = info[cnt][2];
nans.update(pos, val);
cnt++;
}
ans[idx] = nans.query(r);
}
for (int i = 0; i < q; i++) {
cout << ans[i] << '\n';
}
return 0;
}

总结

我也不知道