Codeforces Round #306 (Div. 2) 题解
Posted 人形自走Bug生成器
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #306 (Div. 2) 题解相关的知识,希望对你有一定的参考价值。
旅行传送门
一些闲话:看着难度适中就拿来练手了,没想到居然能AK,顺便纪念下第一次独自敲出2200的题。
A. Two Substrings
题意:给你一个字符串 \\(s\\) ,问 \\(s\\) 中是否同时包含不重叠的子串 \\(AB\\) 和 \\(BA\\) 。
题目分析:扫两遍,第一次先找 \\(AB\\) 再找 \\(BA\\) ,第二次先找 \\(BA\\) 再找 \\(AB\\) ,任意一次满足即符合要求。
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); i++)
#define down(i, x, y) for (register int i = (x); i >= (y); i--)
#define ios \\
ios::sync_with_stdio(false); \\
cin.tie(nullptr); \\
cout.tie(nullptr);
using namespace std;
bool check1(string s)
{
int n = s.length() - 1, f1 = 0, f2 = 0;
for (int i = 0; i < n; i++)
if (s[i] == \'A\' && s[i + 1] == \'B\')
{
f1 = 1;
s[i] = s[i + 1] = \'C\';
break;
}
for (int i = 0; i < n; i++)
if (s[i] == \'B\' && s[i + 1] == \'A\')
{
f2 = 1;
break;
}
return f1 & f2;
}
bool check2(string s)
{
int n = s.length() - 1, f1 = 0, f2 = 0;
for (int i = 0; i < n; i++)
if (s[i] == \'B\' && s[i + 1] == \'A\')
{
f1 = 1;
s[i] = s[i + 1] = \'C\';
break;
}
for (int i = 0; i < n; i++)
if (s[i] == \'A\' && s[i + 1] == \'B\')
{
f2 = 1;
break;
}
return f1 & f2;
}
int main(int argc, char const *argv[])
{
IOS;
string s;
cin >> s;
puts(check1(s) | check2(s) ? "YES" : "NO");
return 0;
}
B. Preparing Olympiad
题意:给你 \\(n\\) 个数,你可以从中挑选任意个放进集合中,问有多少种放法使得集合满足:
- 集合中的元素之和 \\(sum \\in [l,r]\\)
- 集合中元素的最大值与最小值之差 \\(\\leq x\\)
题目分析:\\(n \\leq 15\\) ,暴力 \\(dfs\\) 即可。
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); i++)
#define down(i, x, y) for (register int i = (x); i >= (y); i--)
const int inf = 0x3f3f3f3f;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == \'-\')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = x * 10 + ch - \'0\';
ch = getchar();
}
return x * f;
}
int n, l, r, x, cnt;
std::vector<int> a(20), vis(20);
void dfs(int cur, int mx, int mn, int pre)
{
if (cur > r)
return;
if (cur >= l && mx - mn >= x)
++cnt;
for (int i = pre + 1; i <= n; i++)
{
if (!vis[i])
{
vis[i] = 1;
cur += a[i];
int m1 = std::max(a[i], mx);
int m2 = std::min(a[i], mn);
dfs(cur, m1, m2, i);
vis[i] = 0;
cur -= a[i];
}
}
}
int main(int argc, char const *argv[])
{
n = read(), l = read(), r = read(), x = read();
rep(i, 1, n) a[i] = read();
dfs(0, 0, inf, 0);
printf("%d\\n", cnt);
return 0;
}
C. Divisibility by Eight
题意: 给你一个数 \\(n\\) ,问能否删除其中若干位使得其能被8整除?
题目分析:因为 \\(1000 ÷ 8 = 125\\) ,所以整千数都是 \\(8\\) 的倍数,而原数减去后三位就是整千数,是 \\(8\\) 的倍数。因此原数是不是 \\(8\\) 的倍数,只要看后三位是不是 \\(8\\) 的倍数,那么我们只需特判一二位,三位以上只需看后三位即可。
顺便做个笔记:
-
若一个整数的末位是偶数,则这个数能被 \\(2\\) 整除。
-
若一个整数的数字和能被 \\(3\\) 整除,则这个整数能被 \\(3\\) 整除
-
若一个整数的末尾两位数能被 \\(4\\) 整除,则这个数能被 \\(4\\) 整除
-
若一个整数的末位是 \\(0\\) 或 \\(5\\) ,则这个数能被 \\(5\\) 整除
-
若一个整数能被 \\(2\\) 和 \\(3\\) 整除,则这个数能被 \\(6\\) 整除
-
若一个整数的个位数字截去,再从余下的数中,减去个位数的 \\(2\\) 倍,如果差是 \\(7\\) 的倍数,则原数能被 \\(7\\) 整除。如果差太大或不易看出是否 \\(7\\) 的倍数,就需要继续上述「截尾、倍大、相减、验差」的过程,直到能清楚判断为止。例如,判断 \\(133\\) 是否 \\(7\\) 的倍数的过程如下: \\(13-3×2=7\\) ,所以 \\(133\\) 是 \\(7\\) 的倍数;又例如判断 \\(6139\\) 是否 \\(7\\) 的倍数的过程如下: \\(613-9×2=595\\) , \\(59-5×2=49\\) ,所以 \\(6139\\) 是 \\(7\\) 的倍数,以此类推。
-
若一个整数的末尾三位数能被 \\(8\\) 整除,则这个数能被 \\(8\\) 整除
-
若一个整数的数字和能被 \\(9\\) 整除,则者个整数能被 \\(9\\) 整除
-
若一个整数末位是 \\(0\\) ,则这个数能被 \\(10\\) 整除
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); i++)
#define down(i, x, y) for (register int i = (x); i >= (y); i--)
#define IOS \\
ios::sync_with_stdio(false); \\
cin.tie(nullptr); \\
cout.tie(nullptr);
using namespace std;
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == \'-\')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = x * 10 + ch - \'0\';
ch = getchar();
}
return x * f;
}
int main(int argc, char const *argv[])
{
IOS;
string s;
cin >> s;
int n = s.length(), flag = 0;
for (auto ch : s)
{
if (ch - \'0\' == 8 || ch - \'0\' == 0)
{
cout << "YES" << endl;
cout << ch << endl;
return 0;
}
if (!(ch - \'0\' & 1))
flag = 1;
}
if (!flag || n == 1)
{
cout << "NO" << endl;
return 0;
}
if (n == 2)
{
int num = 10 * (s[0] - \'0\') + s[1] - \'0\';
if (num % 8)
cout << "NO" << endl;
else
{
cout << "YES" << endl;
cout << num << endl;
}
return 0;
}
else
{
rep(i, 0, n - 1)
{
int num = s[i] - \'0\';
rep(j, i + 1, n - 1)
{
num = num * 10 + s[j] - \'0\';
if (!(num % 8))
{
cout << "YES" << endl;
cout << num << endl;
return 0;
}
rep(k, j + 1, n - 1)
{
num = num * 10 + s[k] - \'0\';
if (!(num % 8))
{
cout << "YES" << endl;
cout << num << endl;
return 0;
}
num /= 10;
}
num /= 10;
}
}
cout << "NO" << endl;
}
return 0;
}
D. Regular Bridge
题意:要求构造出一张无向图,图中每个顶点度数均为 \\(k\\) ,且至少存在一条桥边,不存在重边和自环。问能否构造出这样的图?若能则输出构造方案。
题目分析:瞎猜 + 乱搞过的,具体证明和构造方案可以参考这位juju的博客:旅行传送门,思路是一样的(原谅我过低的语文水平)。
稍微解释下就是:题目要求至少存在一条桥边,那么往简单了去想,只需构建一条桥,对桥两边的连通块对称的构造就好。由于桥的存在,桥边的两个端点已经有了 \\(1\\) 的度数,所以我们再分别添加 \\(k-1\\) 个点连接这两个端点使得其度数等于 \\(k\\) ,此时这些端点的度数也为 \\(1\\) ,那就重复之前的步骤再分别添加 \\(k-1\\) 个点和它们相连,最后新添加的点度数为 \\(k-1\\) ,那么只需在每两个点间再连一条边即可。
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); i++)
#define down(i, x, y) for (register int i = (x); i >= (y); i--)
void solve(int k)
{
if (!(k & 1))
{
puts("NO");
return;
}
puts("YES");
printf("%d %d\\n", 4 * k - 2, k * (2 * k - 1));
for (int i = 1; i <= k; i++)
for (int j = 1; j <= k - 1; j++)
printf("%d %d\\n", i, k + j);
for (int i = 2; i <= k; i += 2)
printf("%d %d\\n", i, i + 1);
for (int i = 2 * k; i <= 3 * k - 1; i++)
for (int j = 1; j <= k - 1; j++)
printf("%d %d\\n", i, 3 * k + j - 1);
for (int i = 2 * k + 1; i <= 3 * k - 1; i += 2)
printf("%d %d\\n", i, i + 1);
printf("%d %d\\n", 1, 2 * k);
}
int main(int argc, char const *argv[])
{
int k;
scanf("%d", &k);
solve(k);
return 0;
}
E. Brackets in Implications
题意:给你 \\(n\\) 个数,你可以任意增加括号改变运算顺序,问是否可以构造结果为 \\(0\\) 的蕴含式。
题目分析:首先明确一点,蕴含式当且仅当 \\(1 \\rightarrow 0\\) 时结果才为 \\(0\\) ,因此只有序列最后一位为 \\(0\\) ,答案才可能为 \\(0\\) 。然后我们从 \\(n-1\\) 位向前推,只需要再找到一个子序列能通过构造得到 \\(1\\) ,此时序列为 \\((... \\rightarrow 1 \\rightarrow 0)\\) ,那么不管前面 \\(...\\) 一段是什么,其蕴含 \\(1\\) 的结果也必定为 \\(1\\) ,解决方案必定存在,那么我们怎么找到这样的一个子序列呢?分两种情况讨论:
- \\(a_{n-2}\\) 蕴含 \\(a_{n-1}\\) 本来就为 \\(1\\)
- \\(a_{n-2}\\) 蕴含 \\(a_{n-1}\\) 为 \\(0\\) ,即 \\(a_{n-2}\\) 与 \\(a_{n-1}\\) 分别为 \\(1\\) \\(0\\) ,那就继续往前找直至找到 \\(0\\) ,即 \\(0 \\rightarrow 1 \\rightarrow 1 \\rightarrow 1 \\rightarrow ... \\rightarrow 1 \\rightarrow 1 \\rightarrow 0\\) ,从而构造出计算结果为 \\(1\\) 的子序列
AC代码:
#include <bits/stdc++.h>
#define rep(i, x, y) for (register int i = (x); i <= (y); i++)
#define down(i, x, y) for (register int i = (x); i >= (y); i--)
char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while (!isdigit(ch))
{
if (ch == \'-\')
f = -1;
ch = getchar();
}
while (isdigit(ch))
{
x = x * 10 + ch - \'0\';
ch = getchar();
}
return x * f;
}
int main(int argc, char const *argv[])
{
int n = read();
std::vector<int> a(n + 1), l(n + 1), r(n + 1);
rep(i, 1, n) a[i] = read();
if (n == 1)
{
if (a[1])
puts("NO");
else
{
puts("YES");
printf("0");
}
}
else if (n == 2)
{
if (a[1] == 1 && a[2] == 0)
{
puts("YES");
printf("1->0");
}
else
puts("NO");
}
else
{
if (a[n])
{
puts("NO");
return 0;
}
int flag = 0, pos;
if (a[n - 1] == 0 && a[n - 2] == 1)
{
++r[n - 1], ++l[n - 2];
int p = n - 3;
while (p > 0)
{
++r[n - 1], ++l[p];
if (!a[p])
{
flag = 1, pos = p - 1;
break;
}
--p;
}
}
else
{
++r[n - 1], ++l[n - 2];
flag = 1, pos = n - 3;
}
if (!flag)
{
puts("NO");
return 0;
}
++l[1], ++r[n];
puts("YES");
rep(i, 1, n)
{
while (l[i]--)
printf("(");
printf("%d", a[i]);
if (r[i])
{
while (r[i]--)
printf(")");
if (i ^ n)
printf("->");
}
else
printf("->");
}
}
return 0;
}
以上是关于Codeforces Round #306 (Div. 2) 题解的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #306 (Div. 2) 题解
Codeforces Round #306 (Div. 2) A
「日常训练」Two Substrings(Codeforces Round 306 Div.2 A)
「日常训练」Regular Bridge(Codeforces Round 306 Div.2 D)
「日常训练」Divisibility by Eight(Codeforces Round 306 Div.2 C)
「日常训练」Brackets in Implications(Codeforces Round 306 Div.2 E)