AtCoder Beginner Contest ABC194题解

考研选手为了ec-final开始复健(

A题 I Scream

注意需要将milk solids-not-fat和milk fat加起来就好了

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int > PII;
const int N = 1e5 + 10;


int main(){
#ifndef ONLINE_JUDGE
    freopen("my_in.txt", "r", stdin);
    freopen("my_out.txt", "w", stdout);
#endif
    int a, b;
    scanf("%d %d", &a, &b);
    if(a + b >= 15 && b >= 8) cout<<1<<endl;
    else if(a + b >= 10 && b >= 3) cout<<2<<endl;
    else if(a + b >= 3) cout<<3<<endl;
    else cout<<4<<endl;
    return 0;
}

B题 Job Assignment

由于N的范围很小只有一千,可以直接枚举一下
做的时候没有管范围直接把A和B排了个序,判断一下A和B中的最小值是否来自同一个i,不是的话直接输出二者最大值,是的话就判断一下\(max(A_1, B_2)和max(A_2, B_1)和A_1+B_1\)三者哪个最小就好了

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
typedef pair<int, int > PII;
const int N = 1010;

PII a[N], b[N];

bool cmp(PII x, PII y){
    return x.first < y.first;
}

int main(){
    int n;
    cin>>n;
    for(int i = 0; i < n; i ++){
        scanf("%d %d", &a[i].first, &b[i].first);
        a[i].second = i, b[i].second = i;
    }
    sort(a, a + n, cmp);
    sort(b, b + n, cmp);
    if(a[0].second == b[0].second){
        int x = a[0].first + b[0].first;
        for(int i = 1; i < n; i ++){
            int y = max(b[i].first, a[0].first);
            if(y < x){
                x = y; break;
            }
            else{
                break;
            }
        }
        for(int i = 1; i < n; i ++){
            int y = max(a[i].first, b[0].first);
            if(y < x){
                x = y; break;
            }
            else
                break;
        }
        cout<<x<<endl;
    }
    else {
        cout<<max(a[0].first,b[0].first)<<endl;
    }
    return 0;
}

好像写了很傻的代码

C题 Squared Error

两种方法
1.由于\(|A_i| \leq 200\),可以将这3e5个数全部归到200以内,只用算这200个数的差平方再乘上每个数出现的次数。
2.对题目中的公式进行推导,如下图
process

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;

const int maxn = 3e5 + 10;
vector<int> a(maxn);

int main(){
    int n;
    long long ans = 0, sum = 0;
    scanf("%d", &n);
    for(int i = 0; i < n; i++){
        scanf("%d", &a[i]);
        sum += a[i];
        ans += a[i] * a[i];
    }
    ans *= n;
    ans -= sum * sum;
    cout<<ans<<endl;
    return 0;
}

D题 Journey

是一道dp题
假设当前有i个点已经连通,d[i]代表在此基础上要使图全部连通(即n个点都连通)时所需步数的期望。
通过定义可知起始点为d[n] = 0,需从后往前推
\(d[i] = \frac{n - i}{n}d[i+1] + \frac{i}{n}d[i] + 1\)
也就是有两种状态可以转移至d[i],一种是从d[i+1]中减掉一个已经连通的点——选一个d[i]中未连通的点,所以是(n-i)/n * d[i+1],另一种是从d[i]选一个已连通的点,也就是i/n * d[i],最后再加上这一步的步数1。
化简得到\(d[i] = d[i+1] + \frac{n}{n - i}\)

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 10;
typedef long long ll;
double a[N];

int main(){
    int n;
    cin >> n;
    a[n] = 0.0;
    for(int i = n - 1; i > 0; i --){
        a[i] = a[i + 1] + (double)n / (double)(n - i);
    }
    printf("%.6lf\n", a[1]);
    return 0;
}

E题 Mex Min

求滑动区间最小mex值
用类似滑动窗口做,将第一个区间算完后,将mex值看成从左往右从小到大的一行中第一个空着的地方。考虑几种情况:
1.移出区间的值使mex左边空了一格,mex左移
2.移出和新进区间的值正好相同,mex不变
3.新进区间的值把mex的空填上了,需要继续往右找空的地方
4.在mex的右边进行操作
由于只需要求mex最小值,所以只考虑1的情况就可以了
判断移出区间的值计数是否变为0,变为0则取当前mex和该值的最小值
注意算第一个区间的时候,for循环要循环至max(Ai)+1

#include <bits/stdc++.h>
using namespace std;

const int N = 1500010;
int a[N], ct[N];

int main(){
    int n, m, res = 1e9;
    scanf("%d %d", &n, &m);
    if(n == 1){
        cout<<1<<endl;
        return 0;
    } 
    for(int i = 0; i < n; i ++){
        scanf("%d", &a[i]);
        if(i < m)
            ct[a[i]] ++;
    }
    for(int i = 0; i <= n; i ++){
        if(ct[i] == 0){
            res = i;
            break;
        }  
    }
    for(int i = m; i < n ; i ++){
        int cnt = -1;
        ct[a[i - m]] --;
        ct[a[i]] ++;
        if(ct[a[i - m]] == 0)
            res = min(res, a[i - m]);
        if(res == 0){
            cout<<res<<endl;
            return 0;
        }
    }
    cout<<res<<endl;
    return 0;
}

F题明天补上~

posted @ 2021-03-19 21:08  moomight  阅读(149)  评论(0编辑  收藏  举报