Educational Codeforces Round 70 (Rated for Div. 2)

本文最后更新于:星期四, 二月 3日 2022, 9:15 晚上

A. You Are Given Two Binary Strings…

签到

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

#include <bits/stdc++.h>


using namespace std;

typedef long long ll;

#define N 500010


char x[N], y[N];

int main() {
#ifdef LOCAL_JUDGE
freopen("input.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%s", x + 1);
scanf("%s", y + 1);
int cnt1 = 0;
for (int i = strlen(y + 1); i >= 1; --i) {
if (y[i] != '0') {
break;
}
cnt1++;
}
int res = 0;
for (int i = strlen(x + 1) - cnt1; i >= 1; --i) {
if (x[i] != '0') {
break;
} else {
res++;
}
}
printf("%d\n", res);
}
return 0;
}

B. You Are Given a Decimal String…

题意:给定一个xyx-y计数器,每次只能加xx或者yy,且每次输出个位,现在有一个缺失了的打印结果,问对于一个xy(0x9,0y0)x-y(0\leq x\leq 9, 0\leq y\leq0)最少的填充字符数

思路:预处理xyx-y计数器的ij(0i9,0j9)i-j(0\leq i\leq9,0\leq j\leq 9)ii到达jj的最小填充数字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

#define N 2000010
#define INF 0x3f3f3f3f

char s[N];
ll ans[20][20];
int a[20][20][20][20];

void Init() {
memset(a, 0x3f, sizeof a);
for (int x = 0; x < 10; ++x) {
for (int y = 0; y < 10; ++y) {
for (int o1 = 0; o1 < 10; ++o1) {
for (int o2 = 0; o2 < 10; ++o2) {
for (int i = 0; i < 100; ++i) {
for (int j = 0; j < 100; ++j) {
if (i == 0 && j == 0) {
continue;
}
if ((o1 + i * x + j * y) % 10 == o2) {
a[x][y][o1][o2] = min(a[x][y][o1][o2], i + j);
}
}
}
}
}
}
}
}

int main() {
#ifdef LOCAL_JUDGE
freopen("input.txt", "r", stdin);
#endif
Init();
while (scanf("%s", s + 1) != EOF) {
int len = strlen(s + 1);
for (int x = 0; x < 10; ++x) {
for (int y = 0; y < 10; ++y) {
ans[x][y] = 0;
if (len == 1) {
continue;
}
for (int i = 2; i <= len; ++i) {
int c1 = s[i] - '0', c2 = s[i - 1] - '0';
if (a[x][y][c2][c1] == INF) {
ans[x][y] = -1;
break;
} else {
ans[x][y] += a[x][y][c2][c1] - 1;
}
}
}
}
for (int x = 0; x < 10; ++x) {
for (int y = 0; y < 10; ++y) {
printf("%lld%c", ans[x][y], " \n"[y == 9]);
}
}
}
return 0;
}

C. You Are Given a WASD-string…

题意:给定一个机器人,最多填充一个命令,使得包围住机器人走过路径的矩形的最小面积

思路:填充一个命令==回推一步,枚举到达上下左右边界的位置,回推一步后算面积

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

#define N 2000010
#define INF 0x3f3f3f3f

char s[N];
int Left[N], Right[N], Up[N], Down[N];

void change(int &x, int &y, char c) {
if (c == 'W') {
++y;
} else if (c == 'A') {
--x;
} else if (c == 'S') {
--y;
} else if (c == 'D') {
++x;
}
}

int main() {
#ifdef LOCAL_JUDGE
freopen("input.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%s", s + 1);
int len = strlen(s + 1);
int x = 0, y = 0;
int x1 = INF, x2 = INF, y1 = INF, y2 = INF;
int left = 0, right = 0, up = 0, down = 0;
for (int i = 1; i <= len; ++i) {
change(x, y, s[i]);
if (left > x) {
x1 = i;
left = x;
}
if (right < x) {
x2 = i;
right = x;
}
if (up < y) {
y1 = i;
up = y;
}
if (down > y) {
y2 = i;
down = y;
}
}
ll ans = 1ll * (up - down + 1) * (right - left + 1);
//right
if (x1 != INF) {
x = y = left = right = up = down = 0;
for (int i = 1; i <= len; ++i) {
if (i == x1) {
change(x, y, 'D');
left = min(left, x);
right = max(right, x);
up = max(up, y);
down = min(down, y);
}
change(x, y, s[i]);
left = min(left, x);
right = max(right, x);
up = max(up, y);
down = min(down, y);
}
ans = min(ans, 1ll * (up - down + 1) * (right - left + 1));
}
if (x2 != INF) {
x = y = left = right = up = down = 0;
for (int i = 1; i <= len; ++i) {
if (i == x2) {
change(x, y, 'A');
left = min(left, x);
right = max(right, x);
up = max(up, y);
down = min(down, y);
}
change(x, y, s[i]);
left = min(left, x);
right = max(right, x);
up = max(up, y);
down = min(down, y);
}
ans = min(ans, 1ll * (up - down + 1) * (right - left + 1));
}
if (y1 != INF) {
x = y = left = right = up = down = 0;
for (int i = 1; i <= len; ++i) {
if (i == y1) {
change(x, y, 'S');
left = min(left, x);
right = max(right, x);
up = max(up, y);
down = min(down, y);
}
change(x, y, s[i]);
left = min(left, x);
right = max(right, x);
up = max(up, y);
down = min(down, y);
}
ans = min(ans, 1ll * (up - down + 1) * (right - left + 1));
}
if (y2 != INF) {
x = y = left = right = up = down = 0;
for (int i = 1; i <= len; ++i) {
if (i == y2) {
change(x, y, 'W');
left = min(left, x);
right = max(right, x);
up = max(up, y);
down = min(down, y);
}
change(x, y, s[i]);
left = min(left, x);
right = max(right, x);
up = max(up, y);
down = min(down, y);
}
ans = min(ans, 1ll * (up - down + 1) * (right - left + 1));
}
printf("%lld\n", ans);
}
return 0;
}

D. Print a 1337-string…

题意:构造一个长度不大于1e51e5的字符串,使得13371337子串出现次数为nn

思路:在字符串末尾放一个77,那么13371337出现次数为每个117733的个数xx,贡献为x(x1)2\frac{x(x-1)}{2},同时nn可以分解为若干个x(x1)2\frac{x(x-1)}{2}的累加,构造即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

#define N 2000010

ll n;
char str[N];
int cnt[N];

ll calc(ll x) {
return x * (x - 1) >> 1;
}

int main() {
#ifdef LOCAL_JUDGE
freopen("input.txt", "r", stdin);
#endif
int T;
scanf("%d", &T);
while (T--) {
scanf("%lld", &n);
cnt[0] = 0;
for (int i = 100000; i >= 1; --i) {
ll C = calc(i);
if (C == 0) {
continue;
}
while (n >= C) {
n -= C;
cnt[++cnt[0]] = i;
}
}
str[1] = '7';
int pos = 1, c1 = 0;
for (int i = cnt[0]; i >= 1; --i) {
for (int j = c1; j < cnt[i]; ++j) {
str[++pos] = '3';
++c1;
}
str[++pos] = '1';
}
reverse(str + 1, str + 1 + pos);
str[++pos] = 0;
puts(str + 1);
}
return 0;
}

E.You Are Given Some Strings…

题意:定义f(t,s)f(t,s)表示字符串sstt中出现的次数,现在给定一个tt以及nnss,问i=1nj=1nf(t,si+sj)\sum_{i=1}^{n}\sum_{j=1}^{n}f(t, s_i+s_j)

思路:单独考虑每个sis_i的贡献,那么如果sis_i出现的末尾位置是LiL_i,那么他能和出现的初始位置为Li+1L_i+1的每个jj产生一个贡献。我们用LiL_i表示在ss中末尾位置在tt字符串的ii位置出现字符串个数,RiR_i表示ss中起始位置在tt字符串的ii位置出现的字符串个数,那么答案就是i=1len1LiRi+1\sum_{i=1}^{len-1}L_i\cdot R_i+1其中lenlen表示tt的长度。对于L,RL,R可以用acac自动机处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

#define N 200010

struct Trie {
struct node {
int nxt[26], fail, cnt;

node() {
memset(nxt, -1, sizeof nxt);
cnt = 0;
}
} t[N];

int root, L;

int newnode() {
t[++L] = node();
return L;
}

void Init() {
L = 0;
root = newnode();
}

void insert(const string &s) {
int now = root;
for (char i : s) {
if (t[now].nxt[i - 'a'] == -1)
t[now].nxt[i - 'a'] = newnode();
now = t[now].nxt[i - 'a'];
}
++t[now].cnt;
}

void build() {
queue<int> q;
t[root].fail = root;
for (int i = 0; i < 26; ++i) {
if (t[root].nxt[i] == -1) {
t[root].nxt[i] = root;
} else {
t[t[root].nxt[i]].fail = root;
q.push(t[root].nxt[i]);
}
}
while (!q.empty()) {
int now = q.front();
q.pop();
t[now].cnt += t[t[now].fail].cnt;
for (int i = 0; i < 26; ++i) {
if (t[now].nxt[i] == -1) {
t[now].nxt[i] = t[t[now].fail].nxt[i];
} else {
t[t[now].nxt[i]].fail = t[t[now].fail].nxt[i];
q.push(t[now].nxt[i]);
}
}
}
}

void query(string s, ll *a) {
int now = root;
for (int i = 0, len = s.length(); i < len; ++i) {
now = t[now].nxt[s[i] - 'a'];
a[i] = t[now].cnt;
}
}

void debug() {
for (int i = 1; i <= L; ++i) {
cout << t[i].cnt << " \n"[i == L];
}
}
} trie;

int n;
string s[N], t, tr;
ll L[N], R[N];

int main() {
#ifdef LOCAL_JUDGE
freopen("input.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
while (cin >> t) {
tr = t;
reverse(tr.begin(), tr.end());
memset(L, 0, sizeof L);
memset(R, 0, sizeof R);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> s[i];
}
trie.Init();
for (int i = 1; i <= n; ++i) {
trie.insert(s[i]);
}
trie.build();
trie.query(t, L);;

trie.Init();
for (int i = 1; i <= n; ++i) {
reverse(s[i].begin(), s[i].end());
trie.insert(s[i]);
}
trie.build();
trie.query(tr, R);

int len = t.length();
reverse(R, R + len);

ll ans = 0;
for (int i = 0; i < len; ++i) {
ans += L[i] * R[i + 1];
}
cout << ans << "\n";
}
return 0;
}