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)(补题)