Loading

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;
}
posted @ 2021-02-23 13:16  Frank_Ou  阅读(116)  评论(0编辑  收藏  举报