AtCoder Beginner Contest 210 A~E题解

A - Cabbages

  • 题意
    n n n个物品,初始价格为 x x x,当购买量大于等于 a a a时,那么剩下未购买的物品价格按 y y y处理。求最小价格。

  • 解题思路
    简单贪心,题目中保证了 x > y x >y x>y。需要注意判断 n n n a a a的大小关系。

  • AC代码

/**
  *@filename:A
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-25 15:41
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;

int n,a,x,y;
void solve(){
}
int main(){
    cin >> n >> a >> x >> y;
    if(n <= a){
        cout << n * x << endl;
    }
    else{
        cout << a * x + (n - a) * y;
    }
    solve();
    return 0;
}

B - Bouzu Mekuri

  • 题意
    给你一个 01 01 01字符串,两个人一次取字符串的开头字符,谁先取到 1 1 1字符谁就输。输出输家的名称。

  • 解题思路
    水题,遍历即可。

  • AC代码

/**
  *@filename:B
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-25 15:44
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;

int n;
string s;
int ans;
void solve(){
}
int main(){
    cin >> n >> s;
    for(int i = 0; i < s.size(); ++ i){
        if(s[i] == '1'){
             if(!(i & 1)){
                cout << "Takahashi" << endl;
            }
            else{
                cout << "Aoki" << endl;
            }  
            break;
        }
    }
    solve();
    return 0;
}

C - Colorful Candies

  • 题意
    给你一个序列,问其中长度为 k k k的连续子序列的最大不重复元素数量是多少。

  • 解题思路
    很容易想到双指针滑动检索。注意使用 m a p map map更新元素。

  • AC代码

/**
  *@filename:C
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-25 15:54
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 3e5 + 5;
const int P = 1e9+7;

int n,k,c[N];
unordered_map<int,int> p;//判断是否符合。
void solve(){
    int maxx = 1;
    for(int i = 1; i <= k; ++ i){
        p[c[i]]++;//先将前i个放入map中
    }
    maxx = max(maxx,(int)p.size());
    for(int i = k + 1; i <= n; ++ i){
        p[c[i]] ++;
        p[c[i - k]]--;
        if(p[c[i - k]] == 0)p.erase(c[i - k]);
        maxx = max(maxx,(int)p.size());
    }
    cout << maxx << endl;
}
int main(){
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n; ++ i){
        scanf("%d", &c[i]);
    }
    solve();
    return 0;
}

D - National Railway

  • 题意
    给你一个 n × m n\times m n×m大小的地点,问你需要选择两个地点建地点站,并在其之间建立轨道,问最小花费。

  • 解题思路
    根据题意,实际上建立轨道的花费相当于是它们的曼哈顿距离 × c \times c ×c,所以如果我们建好了一个站,那么相当于我可以行走到下一个地点再建一个站,所以我们可以先记录好前半部分的最小花费。我们可以用 d p [ i ] [ j ] dp[i][j] dp[i][j]来表示已经建好了一个地铁站,且已经走到了 ( i , j ) (i,j) (i,j),为了考虑全面,我们遍历的方向实际上就是东北和东南方向。所以我们要分两次来跑,对于东南方向,状态转移方程易知: d p [ i ] [ j ] = { a i j , d p [ i − 1 ] [ j ] + c , d p [ i ] [ j − 1 ] + c } dp[i][j] = \{a_{ij},dp[i-1][j]+c,dp[i][j-1]+c\} dp[i][j]={aij,dp[i1][j]+c,dp[i][j1]+c}。那么我们处理好 d p dp dp数组之后,还有一点就是如何确定最后一个地铁站建在哪最优,哪很明显,我们直接遍历 d p dp dp数组再枚举我们建立的地铁站即可。

  • AC代码

/**
  *@filename:D
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-25 16:39
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 1000 + 5;
const int P = 1e9+7;
const ll INF = 0x3f3f3f3f3f3f3f;

int n,m,c;
ll a[N][N],dp[N][N],ans[N][N];//其中dp[i][j]表示已经建了一站。且当前处于(i,j)。ans[i][j]则表示最后一站在(i,j)处建的最低成本。
void solve(){
    fill(dp[0],dp[0] + N * N,INF);
    fill(ans[0],ans[0] + N * N,INF);
    //从(1,1)开始往右下走。
    for(int i = 1; i <= n; ++ i){
        for(int j = 1; j <= m; ++ j){
            dp[i][j] = min(a[i][j],min(dp[i - 1][j],dp[i][j - 1]) + c);//设状态转移方程。
        }
    }
    ll minn = INF;
    for(int i = 1; i <= n; ++ i){
        for(int j = 1; j <= m; ++ j){
            ans[i][j] = min(dp[i - 1][j],dp[i][j - 1]) + c + a[i][j];
            minn = min(ans[i][j],minn);
        }
    }
    //从(n,m)开始往左上走。
    for(int i = n; i >= 1; -- i){
        for(int j = 1; j <= m; ++ j){
            dp[i][j] = min(a[i][j],min(dp[i + 1][j],dp[i][j - 1]) + c);
        }
    }
    for(int i = 1; i <= n; ++ i){
        for(int j = 1; j <= m; ++ j){
            ans[i][j] = min(dp[i + 1][j],dp[i][j - 1]) + c + a[i][j];
            minn = min(ans[i][j],minn);
        }
    }
    printf("%lld\n",minn);
}
int main(){
    scanf("%d%d%d", &n, &m, &c);
    for(int i = 1; i <= n; ++ i){
        for(int j = 1; j <= m; ++ j){
            scanf("%lld", &a[i][j]);
        }
    }
    solve();
    return 0;
}

E - Ring MST

  • 题意
    最开始有 n n n个点, 0 0 0条边的图。现在给你 m m m种操作,第 i i i操作可以选择 x , 0 ≤ x < n x,0\leq x <n x,0x<n,然后将 x x x ( x + a i ) m o d    n (x+a_i)\mod n (x+ai)modn这两个顶点之间连边,花费为 c i c_i ci,问你使这 n n n个点的最小花费是多少。

  • 解题思路
    首先要注意一点,相当于是建立最小生成树,而根据Kruskal算法,我们会优先选择权值小的边进行组合,所以我们自然是根据 c i c_i ci来排序。其次,根据这个取余特性,实际上我们是可以重复这个动作获得 g c d ( a i , n ) gcd(a_i,n) gcd(ai,n)个集合,这里我们不做证明。那么当 g c d ( a i , n ) gcd(a_i,n) gcd(ai,n) 1 1 1时则连通。所以我们不断缩小集合即可。

  • AC代码

/**
  *@filename:E
  *@author: pursuit
  *@csdn:unique_pursuit
  *@email: 2825841950@qq.com
  *@created: 2021-07-25 17:13
**/
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int N = 100000 + 5;
const int P = 1e9+7;

struct node{
    int a,c;
    bool operator < (const node &A){
        if(c == A.c){
            return a < A.a;
        }
        return c < A.c;
    }
};
node nodes[N];
int n,m;
void solve(){
    ll ans = 0;
    sort(nodes + 1,nodes + 1 + m);
    for(int i = 1; i <= m; ++ i){
        int temp = __gcd(nodes[i].a,n);
        ans += 1LL * (n - temp) * nodes[i].c;
        n = temp;
        if(n == 1)break;
    }
    printf("%lld\n",n > 1 ? -1 : ans);
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; ++ i){
        scanf("%d%d", &nodes[i].a, &nodes[i].c);
    }
    solve();
    return 0;
}
posted @ 2022-03-26 16:48  unique_pursuit  阅读(44)  评论(0)    收藏  举报