Atcoder ABC134 A-E
传送到AtCoder Beginner Contest 134
A.Dodecagon
给你一个r,让你输出\(3\times r^2\)
B.Golden Apple
给你N个苹果树,告诉你每个工人的工作范围\(i-d \le range \le i+d\),问你把所有的树采摘一遍最少要几个工人。直接输出\(\lceil \frac{N}{2\times d+1} \rceil\)即可。
C.Exception Handling
给你一个长度为\(N\)的序列,让你一次输出去掉第\(i(1\le i\le N)\)个元素后,余下集合内的最大值
这种题做法很多,我选择的是利用\(multiset\)容器储存序列,直接删掉容器中的\(a_i\)后输出最大元素,随后再插回去
AC代码
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <set>
using namespace std;
const int N = 2e6 + 4;
int a[N], n;
multiset<int> se;
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]; se.insert(a[i]);
}
for(int i = 1; i <= n; i++) {
se.erase(se.find(a[i]));
cout << *(--se.end()) << '\n';
se.insert(a[i]);
}
return 0;
}
D.Preparing Boxes
给你一个由\(0\)和\(1\)组成的序列\(A\),让你构造一个同样构造的序列\(B\),使得B中\(i\)的倍数的元素的和取模\(2\)后等于\(a_i\),让你输出什么时候让\(b_i\)等于\(1\)
如果从左往右开始构造,那么\(b_i\)值的改变会对左边和右边产生影响,所以我们应该从右往左开始构造,这样以来只会对左边产生影响。随后求\(B\)中下标为\(i\)的倍数的元素之和,如果不满足\(sum\% 2= a_i\),那就让\(b_i=1\),记录一下\(i\),最后输出即可
AC代码
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
const int N = 2e5 + 100;
int a[N], b[N], n;
vector<int> s;
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];
for(int i = n; i; i--) {
int sum = 0;
for(int j = i; j <= n; j += i) {
sum += b[j];
}
if(sum % 2 != a[i]) b[i] = 1, s.push_back(i);
}
cout << s.size() << '\n';
for(auto v : s) cout << v << ' ';
return 0;
}
E.Sequence Decomposing
给你一个序列 \(A = \{ A_1, A_2, \cdots, A_N \}\)。如果\(A_i\le A_j(i<j)\),那么\(A_i\)和\(A_j\)会涂上相同的颜色。让你求最少要涂几种颜色?
本题的第一个做法是求\(A\)中的最长上升子序列(LIS)最少有多少个:准备一个multiset
容器,从头开始遍历序列,将\(a_i\)插入容器中,插入前查找容器中第一个大于等于\(a_i\)的元素,如果容器中存在一个元素大于等于\(a_i\),就将该元素从容器中删除,最后输出容器内元素的个数。该做法最后在容器内保留的就是每段LIS的末尾
第二个做法是利用狄尔沃斯(Dilworth)定理,得到"把一个数列划分成最少的最长上升子序列(LIS)的数目就等于这个数列的最长不上升子序列的长度"的结论,然后利用deque
或反转序列,求出该序列中的最长不上升子序列的长度
AC代码(做法1)
#include <iostream>
#include <algorithm>
#include <set>
using namespace std;
int n, x;
multiset<int> se;
int main() {
cin >> n;
for(int i = 0; i < n; i++) {
int x;
scanf("%d", &x);
auto it = se.lower_bound(x);
if(it!= se.begin()) se.erase(--it);
se.insert(x);
}
cout << se.size() << '\n';
return 0;
}
AC代码(做法2.1)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <deque>
using namespace std;
const int N = 1e5 + 30;
int a[N];
int n;
int main() {
deque<long long> dq;
scanf("%d", &n);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) {
int p = lower_bound(dq.begin(), dq.end(), a[i]) - dq.begin();
if(!p) dq.push_front(a[i]);
else dq[p - 1] = a[i];
}
cout << dq.size() << '\n';
return 0;
}
AC代码(做法2.2)
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 1e5 + 30;
int a[N], dp[N];
int n, p;
int main() {
scanf("%d", &n);
for(int i = n; i; i--) scanf("%d", &a[i]);
for(int i = 1; i <= n; i++) {
if(a[i] >= dp[p]) {
dp[++p] = a[i];
}
else *upper_bound(dp + 1, dp + 1 + p, a[i]) = a[i];
}
cout << p << '\n';
return 0;
}