Educational Codeforces Round 70
Posted dup4
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Educational Codeforces Round 70相关的知识,希望对你有一定的参考价值。
目录
Contest Info
Solved | A | B | C | D | E | F |
---|---|---|---|---|---|---|
5/6 | ? | ? | ? | ? | ? | - |
- O 在比赛中通过
- ? 赛后通过
- ! 尝试了但是失败了
- - 没有尝试
Solutions
A. You Are Given Two Binary Strings...
题意:
给出两个数字\(x, y\),令\(f(x)\)为\(x\)的二进制表示,现在要选择一个\(k\)使得\(s_k = f(x) + f(y) \cdot 2^k\)的字典序最小。
思路:
考虑乘上\(2^k\)相当于让\(f(y)\)左移\(k\)位,那么我们肯定要让\(f(y)\)的最后一位\(1\)移到离\(f(x)\)最近的一个\(1\)和它进位之后,这样翻转之后字典序是最小的。
代码:
#include <bits/stdc++.h>
using namespace std;
#define N 100010
char s[N], t[N];
int main()
int T; scanf("%d", &T);
while (T--)
scanf("%s%s", s + 1, t + 1);
int lens = strlen(s + 1);
int lent = strlen(t + 1);
int post = 0;
for (int i = lent; i >= 1; --i)
if (t[i] == '1')
post = lent - i;
break;
int res = 0;
for (int i = lens - post; i >= 1; --i)
if (s[i] == '1')
res = lens - post - i;
break;
printf("%d\n", res);
return 0;
B. You Are Given a Decimal String...
题意:
有\(x-y\)计数器,它是这样工作的:
- 初始时数值为\(0\)
- 给数值加上\(x\)或者\(y\),然后输出数值模\(10\)后的结果
- 重复第二步操作,直到输出自己满意的序列
现在给定一段序列,问对于\(x \in [0, 9], y \in [0, 9]\)的\(100\)种计数器,最少需要增加多少数才能使得输出的序列是x-y$计数器合法输出来的?
思路:
考虑对于序列中间隔的两个数\(s[i]\)和\(s[i + 1]\),我们定义它们之间的差值为\((s[i + 1] - s[i] + 10) \% 10\),因为是数值的最后一位,所以它们的真实差距肯定可以写成\(10k + (s[i + 1] - s[i])\),但是我们并不需要关心\(k\)是多少。
我们只需要知道需要多少个\((px + qy) \% 10 = (s[i + 1] - s[i] + 10) \% 10\)。
这个暴力枚举一下\(p, q\)即可,而显然\(p \in [0, 9], q \in [0, 9]\),因为存在模\(10\)操作,\((px + qy) \% 10 = (p \% 10 x + q \% 10 ) \% 10\)
代码:
#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 2e6 + 10;
char s[N];
int n, b[20];
void Min(int &x, int y)
if (x > y) x = y;
int main()
while (scanf("%s", s + 1) != EOF)
n = strlen(s + 1);
for (int x = 0; x < 10; ++x)
for (int y = 0; y < 10; ++y)
for (int k = 0; k < 10; ++k) b[k] = INF;
for (int p = 0; p < 10; ++p)
for (int q = 0; q < 10; ++q) if (p | q)
Min(b[(p * x + q * y) % 10], p + q - 1);
int ans = 0;
for (int i = 1; i < n; ++i)
int t = (s[i + 1] - s[i] + 10) % 10;
if (b[t] == INF)
ans = -1;
break;
ans += b[t];
printf("%d%c", ans, " \n"[y == 9]);
return 0;
C. You Are Given a WASD-string...
题意:
有一个机器人,现在给出一系列行走步骤,问能否在任意处添加一个步骤,使得它的行动范围尽量小。
行动范围的定义为用一个最小的矩形框住它的行动路径。范围即为矩形的面积。
思路:
将横竖分开考虑,如果可以缩小行动范围,那么必然是长缩短一或者宽缩短一。
我们考虑什么时候边长可以缩短一:
- 考虑
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200010
char s[N];
int main()
int T; scanf("%d", &T);
while (T--)
scanf("%s", s + 1);
int n = strlen(s + 1);
int nowx = 0, nowy = 0;
int up = 0, down = 0, left = 0, right = 0;
int gup = 0, gdown = 0, gleft = 0, gright = 0;
for (int i = 1; i <= n; ++i)
if (s[i] == 'W') --nowx;
if (s[i] == 'S') ++nowx;
if (s[i] == 'A') --nowy;
if (s[i] == 'D') ++nowy;
up = min(up, nowx);
down = max(down, nowx);
left = min(left, nowy);
right = max(right, nowy);
gup = max(gup, nowx - up);
gdown = max(gdown, down - nowx);
gleft = max(gleft, nowy - left);
gright = max(gright, right - nowy);
ll x[2], y[2];
x[0] = max(gup, gdown);
x[1] = max(1ll * (gup || gdown), x[0] - (gup != gdown));
y[0] = max(gleft, gright);
y[1] = max(1ll * (gleft || gright), y[0] - (gleft != gright));
printf("%lld\n", min((x[0] + 1) * (y[1] + 1), (x[1] + 1) * (y[0] + 1)));
return 0;
D. Print a 1337-string...
题意:
构造一个序列,这个序列只包含\(\1, 3, 7\\),并且一共有\(n\)的子序列是\(1337\)
思路:
考虑最后一位放\(7\)。
然后放\(x\)个\(3\)。
那么每放一个\(1\)可以产生\([1, \fracx(x - 1)2]\)个\(1337\)。
那么考虑从大到小贪心放即可,总能放完。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 100010
ll n;
ll f(ll x)
return x * (x - 1) / 2;
int main()
int T; scanf("%d", &T);
while (T--)
scanf("%lld", &n);
for (int i = 32000; i >= 2; --i)
while (f(i) <= n)
n -= f(i);
putchar('1');
putchar('3');
assert(n == 0);
puts("37");
return 0;
E. You Are Given Some Strings...
题意:
给出一个文本串\(T\),和若干个模式串\(S_i\),定义\(f(t, s)\)为\(s\)在\(t\)中出现的次数。
计算下式:
\[
\begineqnarray*
\sum\limits_i = 1^n \sum\limits_j = 1^n f(t, s_i + s_j)
\endeqnarray*
\]
思路:
考虑\(T\)对整体的贡献,即使\(T\)中存在多少个子串,使得可以从某个中间位置切开,使得左右两边都是模式串。
那么枚举这个中间位置即可,做两边\(AC\)自动机,求出\(f[i], g[i]\),分别表示以\(i\)结尾的模式串匹配次数和以\(i\)开头的模式串匹配次数。
那么乘一乘即是结果。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 200010
int n;
string s[N], t, tr;
ll f[N], g[N];
#define ALP 26
struct ACAM
struct node
int nx[ALP], fail;
int cnt;
node()
memset(nx, -1, sizeof nx);
cnt = 0;
t[N];
int root, tot;
int que[N], ql, qr;
//节点从1开始
int newnode()
++tot;
t[tot] = node();
return tot;
void init()
tot = 0;
root = newnode();
void insert(string s)
int len = s.size();
int now = root;
for (int i = 0; i < len; ++i)
if (t[now].nx[s[i] - 'a'] == -1)
t[now].nx[s[i] - 'a'] = newnode();
now = t[now].nx[s[i] - 'a'];
++t[now].cnt;
void build()
ql = 1, qr = 0;
t[root].fail = root;
for (int i = 0; i < ALP; ++i)
if (t[root].nx[i] == -1)
t[root].nx[i] = root;
else
t[t[root].nx[i]].fail = root;
que[++qr] = t[root].nx[i];
while (ql <= qr)
int now = que[ql++];
t[now].cnt += t[t[now].fail].cnt;
for (int i = 0; i < ALP; ++i)
if (t[now].nx[i] == -1)
t[now].nx[i] = t[t[now].fail].nx[i];
else
t[t[now].nx[i]].fail = t[t[now].fail].nx[i];
que[++qr] = t[now].nx[i];
void query(string s, ll *f)
int len = s.size();
int now = root;
for (int i = 0; i < len; ++i)
now = t[now].nx[s[i] - 'a'];
f[i] = t[now].cnt;
ac;
int main()
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
while (cin >> t)
tr = t; reverse(tr.begin(), tr.end());
cin >> n;
ac.init();
for (int i = 1; i <= n; ++i) cin >> s[i], ac.insert(s[i]);
ac.build();
ac.query(t, f);
ac.init();
for (int i = 1; i <= n; ++i)
reverse(s[i].begin(), s[i].end());
ac.insert(s[i]);
ac.build();
ac.query(tr, g);
ll res = 0;
int len = t.size();
reverse(g, g + len);
for (int i = 0; i < len - 1; ++i)
res += f[i] * g[i + 1];
cout << res << "\n";
return 0;
以上是关于Educational Codeforces Round 70的主要内容,如果未能解决你的问题,请参考以下文章
Educational Codeforces Round 7 A
Educational Codeforces Round 7
Educational Codeforces Round 90
Educational Codeforces Round 33