SDUT 2021 Spring Individual Contest(for 20) - 17(补题)

Posted 佐鼬Jun

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SDUT 2021 Spring Individual Contest(for 20) - 17(补题)相关的知识,希望对你有一定的参考价值。

题目链接: link.

A - Alphabet

思路: 就是字符串版的最长上升子序列,用26减去最长的数量,就是要添加的字符数量。

#include<bits/stdc++.h>
using namespace std;
string s;
int dp[1000];
int main() {
    getline(cin,s);
    char now='a';
    int x=0;
    for(int i=0;i<s.size();i++) {
        for(int j=0;j<i;j++) {
            if(s[i]>s[j]) {
                dp[i]=max(dp[i],dp[j]+1);
            } 
        }
        x=max(dp[i],x);
    }
    
    printf("%d\\n",26-x-1);
    return 0;
}

B - Barbells

题意: 给n个空杆,给m个杠铃片,往空杆上放杠铃片,为了安全要保证空杆左右两边的杠铃片重量要相等。最后输出所有把杠铃片放在空杆上重量的所有情况
思路:对于每个杠铃都有放在右边,左边和不放的选择。利用三进制,对于每一位置上的数字,如果是0,就不选,是1就左边,是2就右边
这样就把所有杠铃的情况都列举出来了。当选完后,如果左右两边相等那就与空杆的重量加起来放进set集合里等待输出。
要注意的点就是开long long

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <set>
using namespace std;
#define ll long long
int n, m;
set<ll> res;
ll a[15], b[15];
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        scanf("%lld\\n", &a[i]);
    }
    int t = 1;  //3的m次方
    for (int i = 0; i < m; i++) {
        scanf("%lld", &b[i]);
        t *= 3;
    }
    for (int i = 0; i < t; i++) {
        ll na = 0, nb = 0;     //代表左右两边的重量
        int k = 0, temp = i;   //分别代表选的杠铃,和当前三进制的数字
        while (temp) {
            if (temp % 3 == 1) na += b[k];
            if (temp % 3 == 2) nb += b[k];
            k++;
            temp /= 3;
        }
        if (na == nb) {      //左右两边重量相同
            for (int j = 0; j < n; j++) {
                ll ans = na + nb + a[j];
                res.insert(ans);
            }
        }
    }
    set<ll>::iterator it;
    for (it = res.begin(); it != res.end(); it++) {
        printf("%lld\\n", *it);
    }
    return 0;
}

C.暂时没能力补,学完后,再补

D - Cameras

题意: n个房子,k个摄像头,要求每连续r个房子,至少要有两个或以上房子有摄像头,现在给k个摄像头的位置,问你再至少补充几个摄像头,就能满足要求。
思路贪心,从左往右贪心,如果当前位置是pos,那么就看从pos到pos+r-1,[pos,pos+r-1]这个长度为r区间的房子是否有两个或以上的摄像头。
如果有两个或以上的摄像头,那就不管了
如果少于两个,那就尽量靠右放,从右往左扫,先看pos+r-1这个位置是否有摄像头,没有就加摄像头,有的话,有往左移动看看,只要这个长度为r区间的摄像头数量大于等于2,看下一个区间。
贪心,贪的是,放摄像头的位置,尽量靠右放(在长度为r的区间内),因为靠右放,可以对后面的区间的摄像头数量做贡献,越往右放,对后面越多的摄像头做的贡献越大。
如果动态查询区间的摄像头数量,和再加了摄像头后,影响区间的摄像头数量?
利用树状数组(线段树)来动态完成区间查询和单点修改的操作。并用st[]数组来标记那个房子按了摄像头。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define ll long long
const int N = 1e5 + 10;
int n, k, r;
int tr[N];
bool st[N];
//树状数组
int lowbit(int x) { return x & -x; }
void add(int x, int c) {
    for (int i = x; i <= n; i += lowbit(i)) {
        tr[i] += c;
    }
}
int sum(int x) {
    int res = 0;
    for (int i = x; i; i -= lowbit(i)) {
        res += tr[i];
    }
    return res;
}

int main() {
    scanf("%d%d%d", &n, &k, &r);
    for (int i = 1; i <= k; i++) {
        int x;
        scanf("%d", &x);
        st[x] = 1;  //标记有摄像头的房子
        add(x, 1);  //当前房子有摄像头
    }
    int ans = 0;
    for (int i = 1; i <= n - r + 1; i++) {
        int res = sum(i + r - 1) - sum(i - 1);  //区间查询摄像头数量
        if (res < 2) {
            //从右往左扫,来放摄像头
            for (int j = i + r - 1; j >= i; j--) {
                if (res >= 2) {
                    break;
                }
                if (!st[j]) {
                    add(j, 1);
                    st[j] = 1;
                    ans++;
                    res++;
                }
            }
        }
    }
    printf("%d\\n", ans);
    return 0;
}

E - Contest Score

题意:n个问题,先读前k个问题,然后选择时间最短的问题解决,解决完问题后,再读下一个的问题,读完又开始选择读完的时间最短的问题解决,最后输出总罚时,罚时就是提交每个题时的时间之和。
思路: 利用优先队列,读完的题就放在优先队列中,每次解决问题,都选优先队列的堆顶(耗时最小的),最后把所有提交题的时间加起来,算总和。

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
#define ll long long
const int N = 311;
int n, k;
int a[N];

priority_queue<int, vector<int>, greater<int> > q;

int main() {
    scanf("%d%d", &n, &k);

    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }

    for (int i = 1; i <= k; i++) {
        q.push(a[i]);
    }

    ll ans = 0, res = 0, pre = 0;
    int now = k + 1;

    while (!q.empty()) {
        res = pre + q.top();
        q.pop();
        pre = res;
        ans += res;
        if (now <= n) {
            q.push(a[now++]);
        }
    }
    printf("%lld\\n", ans);
    return 0;
}

F - Equality

签到题,就是问你等式是否相等。

#include <bits/stdc++.h>
using namespace std;
int a, b, c;
char op1, op2;
int main() {
    scanf("%d + %d = %d", &a, &b, &c);
    if (a + b == c)
        puts("YES");
    else
        puts("NO");
    return 0;
}

G - Gravity

题意: 给你一个图,图上有苹果,障碍物和空地,让你模拟重力,苹果在下降过程中,碰见空地就下降,碰见障碍物就停下,最终让你把重力作用完的图,输出出来。
思路: 就每一列从下往上扫苹果,扫到苹果就往下落,知道碰见障碍物或者苹果。需要注意的点就是会有多个苹果,不能误以为每一列只有一个苹果,这也就是从下往上扫的原因(个人理解,有更好的做法,欢迎讲解)

#include <bits/stdc++.h>
using namespace std;
int n, m;
char a[100][100];
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        scanf("%s", a[i]);
    }
    for (int i = m - 1; i >= 0; i--) {
        for (int j = n - 1; j >= 0; j--) {
            if (a[j][i] == 'o') {
                for (int k = j + 1; k < n; k++) {
                    if (a[k][i] == '.') {
                        a[k][i] = 'o';
                        a[k - 1][i] = '.';
                    } else if (a[k][i] == 'o' || a[k][i] == '#') {
                        break;
                    }
                }
            }
        }
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            printf("%c", a[i][j]);
        }
        printf("\\n");
    }
    return 0;
}

H - Islands

题意: 有一张图其中有三种字符‘L’代表陆地,‘W’代表水,‘C’代表云,求出这张图中岛屿的最小数量。也就是其中‘L’和‘W’都是确定的但是‘C’是可以变化的可以看做是‘W’或是‘L’。
一个岛屿是一组相连的陆地单元。如果两个单元共享一条边,就被认为是相连的。
给出图像,确定符合给定信息的最小的岛屿数量。
思路: 就是dfs+bfs的结合,因为要求最小的岛屿数量,那肯定陆地之间相连是最好的,连起来后就会看成一个岛屿。这时,当从一个陆地往外扫,如果遇见陆地,那就把它放在一个陆地上,如果时云,那就把它看成岛屿(相当于拓宽岛屿的边界,方便与之后的陆地相连,从而减少岛屿的数量),这里扫过的陆地和云(被看成陆地的)就不需要再扫了(节省时间),因为在第一次扫过后,他们一定会被归并在哪个岛屿中,所以不必再扫,所以在扫完之后,只需把这些地方变成水,就能避免下一次再到这个陆地或云了。
当然,把云看成陆地,是在云朵与陆地相连的情况,否则,云朵与陆地不相连,却看成陆地,就会多出一个岛屿,不相连的云朵,看成水就行,这也是样例1输出0的原因。

#include <bits/stdc++.h>
using namespace std;
const int N = 100;
int n, m;
int res;
char a[N][N];
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
bool check(int x, int y) {
    if (x < 0 || x >= n || y < 0 || y >= m || a[x][y] == 'W') {
        return 0;
    }
    return 1;
}
void dfs(int x, int y) {
    for (int i = 0; i < 4; i++) {
        int nx = x + dx[i];
        int ny = y + dy[i];
        if (check(nx, ny)) {
            a[nx][ny] = 'W';
            dfs(nx, ny);
        }
    }
}
int main() {
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++) {
        scanf("%s", a[i]);
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (a[i][j] == 'L') {
                res++;
                dfs(i, j);
            }
        }
    }
    printf("%d\\n", res);
    return 0;
}

I - Mismatched Socks

题意: 给n种颜色袜子,每种颜色的袜子都有m个,每次都要穿两种不同颜色的袜子,问能穿几次。
思路如果最大的袜子数>=其他袜子的数之和,那么显然此时的结果一定为其他袜子的数之和。
反之如果最大的袜子数<其他袜子的数之和,则说明每个袜子的个数都是小于sum/2的
第一种情况好想,就是其他袜子,都和最多的哪个袜子数配对就行
第二种情况就是,把所有的袜子按照顺序摆好,第1个袜子和第sum/2+1个配对,第2个和第sum/2+2配对,因为最大的袜子数小于其他袜子数之和,所以第i个和第i+sum/2,一定不是同一个颜色,否则这种颜色袜子数就大于等于其他袜子数了。通过一一配对,如果是奇数,就剩下一个袜子,如果是偶数,就一一配对完成。
例如a[1]=2,a[2]=2,a[3]=3 ,1 1 2 2 3 3 3,sum/2=3 第1个和第4个配对,第2个和第5个,第3个和第6个配对,第7个剩下。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
int n;
ll a[1010];
ll sum;
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%lld", &a[i]);
        sum += a[i];
    }
    sort(a + 1, a + n + 1);
    if (sum >= a[n] * 2) {
        printf("%lld\\n", sum / 2);
    } else {
        printf("%lld\\n", sum - a[n]);
    }
    return 0;
}

K - Six Sides

题意: 两个人分别有一个6面的骰子,两人投骰子,拼点数,谁大谁赢,问第一个人赢得概率
思路: ans=第一个人赢得次数/(36-平局数),总共就6*6种情况,只要注意精度就行。

#include <bits/stdc++.h>
using namespace std;
int a[7], b[7];
double res;
double sum;
int main() {
    for (int i = 1; i <= 6; i++) scanf("%d", &a[i]);
    for (int i = 1; i <= 6; i++) scanf("%d", &b[i]);
    sort(a + 1, a + 7);
    sort(b + 1, b + 7);
    for (int i = 1; i <= 6; i++) {
        for (int j = 1; j <= 6; j++) {
            if (aSDUT 2021 Spring Individual Contest(for 20) - 1补题

SDUT 2021 Spring Individual Contest(for 20) - 17(补题)

SDUT 2021 Spring Individual Contest(for 20) - 15(补题)

SDUT 2021 Summer Individual Contest - 2(for 20)(补题)

SDUT 2021 Winter Individual Contest - N(B-Derangement)

2021-08-03SDUT 2021 Summer Individual Contest - 4(for 20)(补题)