传送到AtCoder Beginner Contest 134
A.Dodecagon
给你一个r,让你输出(3 imes r^2)
B.Golden Apple
给你N个苹果树,告诉你每个工人的工作范围(i-d le range le i+d),问你把所有的树采摘一遍最少要几个工人。直接输出(lceil frac{N}{2 imes d+1} ceil)即可。
C.Exception Handling
给你一个长度为(N)的序列,让你一次输出去掉第(i(1le ile 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()) << '
';
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() << '
';
for(auto v : s) cout << v << ' ';
return 0;
}
E.Sequence Decomposing
给你一个序列 (A = { A_1, A_2, cdots, A_N })。如果(A_ile 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() << '
';
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() << '
';
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 << '
';
return 0;
}