AtCoder Beginner Contest 132 解题报告(A ~ E)

比赛地址:AtCoder Beginner Contest 132

A - Fifty-Fifty

题目大意:给你一个长度为 \(4\) 的仅由大写字母组成的字符串,问你在这个字符串中是否出现了两个不同的字母,且每个字母各出现了两次。

解题思路:暴力模拟即可,不过既要判断相同,也要判断不同。

#include <cstdio>

char str[5];

int main() {
	scanf("%s", str + 1);
	if ((str[1] == str[2]) && (str[3] == str[4]) && (str[1] != str[3]))
		printf("Yes");
	else if ((str[1] == str[3]) && (str[2] == str[4]) && (str[1] != str[2]))
		printf("Yes");
	else if ((str[1] == str[4]) && (str[2] == str[3] && (str[1] != str[2])))
		printf("Yes");
	else
		printf("No");
	return 0;
}

B - Ordinary Number

题目大意:给你一个 \(1\sim n\) 的排列 \(\{a_1,a_2,\cdots ,a_n\}\) ,问你在这个排列中有多少个 \(i\ (1 < i < n)\) 满足 \(a_i\)\(a_{i - 1},a_i,a_{i + 1}\) 中第二小的数。

解题思路:这是一道比较有趣的枚举判断题,因为在判断条件是否成立时可以想出多种解法,比如说直接暴力写很多个 ifelse if ,或者利用三个数中第二大的数的性质:\((a_i - a_{i - 1})(a_i - a_{i + 1}) < 0\) 来减少码量。

#include <cstdio>

const int MAXN = 25;

int n, ans;
int arr[MAXN];

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &arr[i]);
	}
	for (int i = 2; i < n; ++i) {
		if ((arr[i] - arr[i - 1]) * (arr[i] - arr[i + 1]) < 0)
			++ans;
	}
	printf("%d", ans);
	return 0;
}

C - Divide the Problems

题目大意:有 \(n\)\(n\) 为偶数)个题目,每个题目有一个难度值 \(d_i\) ,现在要确定一个定值 \(k\) ,难度值低于 \(k\) 的题目被用作 ABC 试题,不低于 \(k\) 的题目被用作 ARC 试题,求使得两种比赛试题个数相等的 \(k\) 的个数。

解题思路:将难度值排序,找出最中间的两个难度值 \(l,r\) ,那么答案就是区间 \((l,r]\) 中整数的个数(注意难度值等于 \(k\) 的题目的去向)。

#include <cstdio>
#include <algorithm>

const int MAXN = 1e5 + 5;

int n;
int arr[MAXN];

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%d", &arr[i]);
	}
	std::sort(arr + 1, arr + n + 1);
	printf("%d", arr[(n >> 1) + 1] - arr[n >> 1]);
	return 0;
}

D - Blue and Red Balls

题目大意:有 \(k\) 个蓝球和 \(n - k\) 个红球摆成一列,现在取球者每次可以将连续的一段蓝球取走,直到所有的蓝球全部被取走,对于每个 \(1\le i\le k\) ,求要取 \(i\) 次才能取走所有的蓝球的摆放球的方案数。

解题思路:首先考虑蓝球,要取 \(i\) 次才能将所有蓝球取走,我们就需要将所有的蓝球分成 \(i\) 个部分,这个利用插板法可以得到方案数为 \(\binom{i - 1}{k - 1}\),现在考虑红球,由于我们的蓝球已经摆放好,我们就只需要将红球插入到蓝球两个部分之间的空隙中去即可,这个时候我们可以将蓝球的每一个部分看成一个隔板,要将红球分成若干个部分,而且任意两个隔板之间不能没有红球,但是隔板的某一侧可以没有红球,所以就相当于有 \(n - k + 1\) 个地方来放置隔板,其方案数为 \(\binom{i}{n - k + 1}\) ,将两者相乘即得到答案。

值得注意的是:在计算的过程中,有可能会出现 \(i > n - k + 1\) 的情况吗,这种情况出现的原因就是红球太少了,不能够满足 “任意两个隔板之间不能没有红球” 这个情况,对应的值应该为 \(0\)

#include <cstdio>

typedef long long int ll;

const int MAXN = 2005;
const int mod = 1e9 + 7;

int n, k;
ll C[MAXN][MAXN];

ll get_C(int x, int y) {
	if (x < y)
		return 0;
	if (C[x][y])
		return C[x][y];
	if ((y == 0) || (y == x))
		C[x][y] = 1;
	else
		C[x][y] = (get_C(x - 1, y) + get_C(x - 1, y - 1)) % mod;
	return C[x][y];
}

int main() {
	scanf("%d%d", &n, &k);
	for (int i = 1; i <= k; ++i) {
		printf("%lld\n", get_C(k - 1, i - 1) * get_C(n - k + 1, i) % mod);
	}
	return 0;
}

E - Hopscotch Addict

题目大意:给你一个无边权的有向图 \(G\) ,规定一次必须走 \(3\) 步,问你最少走多少次能从节点 \(s\) 走到 \(t\) ,无解输出 \(-1\)

解题思路:要解决这个问题,我们只需求出从 \(s\)\(t\) 的所有长度为 \(3\) 的倍数的路径中,最短的路径长度是多少。我们考虑 DP ,可以令 \(dp[i][j]\) 表示从节点 \(s\)\(i\) 的所有长度模 \(3\)\(j\) 的路径中,最短的路径的长度,那么初始条件就是 \(dp[s][0] = 0\) ,转移方程就是 \(dp[v][(i + 1)\ Mod\ 3] = dp[u][i] + 1\) (边 \(u\to v\in G\),且 \(dp[v][(i + 1)\ Mod\ 3]\) 未被赋过值),由于没有边权,我们采用 BFS 的方式去进行转移可以保证每个 \(dp[i][j]\) 都是最小的,最后的答案就是 \(\frac{dp[n][0]}{3}\)

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>

const int MAXN = 1e5 + 5;

int n, m, u, v, s, t;
int dp[MAXN][3];

struct node {
    int nv, flag;
    node(int vv = 0, int ff = 0) {
        nv = vv;
        flag = ff;
    }
};

std::vector<int> con[MAXN];
std::queue<node> q;

void ins(int start, int end) {
    con[start].push_back(end);
}

void bfs() {
    dp[s][0] = 0;
    q.push(node(s, 0));
    while (!q.empty()) {
        int nv = q.front().nv, nf = q.front().flag;
        for (int i = 0; i < con[nv].size(); ++i) {
            int tv = con[nv][i];
            if (dp[tv][(nf + 1) % 3] == -1) {
                dp[tv][(nf + 1) % 3] = dp[nv][nf] + 1;
                q.push(node(tv, (nf + 1) % 3));
            }
        }
        q.pop();
    }
}

int main() {
    scanf("%d%d", &n, &m);
    while (m--) {
        scanf("%d%d", &u, &v);
        ins(u, v);
    }
    scanf("%d%d", &s, &t);
    memset(dp, -1, sizeof(dp));
    bfs();
    if (dp[t][0] == -1)
        printf("-1");
    else 
        printf("%d", dp[t][0] / 3);
    return 0;
}
posted @ 2019-07-10 23:23  lornd  阅读(275)  评论(0编辑  收藏  举报