Educational Codeforces Round 40 (Rated for Div. 2) Partial Solution

从这里开始

  • 小结
  • 题目列表
  • Problem A Diagonal Walking
  • Problem B String Typing
  • Problem C Matrix Walk
  • Problem D Fight Against Traffic
  • Problem E Water Taps
  • Problem F Runner‘s Problem
  • Problem G Castle Defense
  • Problem H Path Counting
  • Problem I Yet Another String Matching Problem

小结

  这次练习,感觉自己存在很多细节的问题。

  比如,前3个题很搞笑,被罚了4次时(A题是写了假贪心,B题是忘了条件,C题是忽略细节)。同时时间也安排的不是很好,比如F题的代码很长,但是我先去写了F,再去写G题,到时Penalty再度变高。

  还有件有趣的事,切完D题,输地址时输成了F题(大概是我字母表背得有点"好"),成功跳过E题。

  最后看E题,没仔细看读入,发现样例有毒,手算始终不对。时间再度-10min。

  最后比较悲催的是H和I根本没时间看。虽然估计看了也做不起。

  唯一感到比较欣慰的是多年做cf的题,英语水平有提升(大概是一场比赛题面的单词本来就不多),基本不用翻译就能读懂题目。

Problem A Diagonal Walking

题目大意

  给定一个只包含‘L‘和‘R‘的字符串,你可以将"LR"或者‘RL"替换为"D"。问能使串长能变成的最小值。

  最开始感觉可以贪心。然后:

  改成dp,成功AC。(为什么A题会是dp,没道理啊。。)

Code

 1 /**
 2  * Codeforces
 3  * Problem#954A
 4  * Accepted
 5  * Time: 31ms
 6  * Memory: 0k
 7  */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11
12 const int inf = 2000;
13
14 int n;
15 char str[105];
16 int f[105][2];
17
18 inline void init() {
19     scanf("%d", &n);
20     scanf("%s", str);
21 }
22
23 inline void solve() {
24     f[0][0] = 1, f[0][1] = inf;
25     for (int i = 1; i < n; i++) {
26         if (str[i] != str[i - 1])
27             f[i][1] = f[i - 1][0];
28         else
29             f[i][1] = inf;
30         f[i][0] = min(f[i - 1][1], f[i - 1][0]) + 1;
31     }
32     printf("%d", min(f[n - 1][0], f[n - 1][1]));
33 }
34
35 int main() {
36     init();
37     solve();
38     return 0;
39 }

Problem A

Problem B String Typing

题目大意

  有一台打字机,要输入1个字符串,有两种操作:

  1. 向末尾输入一个字符
  2. 将当前输入的字符串复制一遍粘在后面

  操作2只能使用1次。问最少的操作次数。

  没看到只能用1次,傻傻地写了个dp。并成功获得了:

  然后急急忙忙去加个状态。

  其实只能用1次直接贪心就好了。当减少的操作次数最多的时候用操作2.

Code

 1 /**
 2  * Codeforces
 3  * Problem#954B
 4  * Accepted
 5  * Time: 31ms
 6  * Memory: 0k
 7  */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11
12 int n;
13 char str[105];
14 int f[105][2];
15
16 inline void init() {
17     scanf("%d", &n);
18     scanf("%s", str + 1);
19 }
20
21 boolean equal(int l1, int l2, int len) {
22     for (int i = 0; i < len; i++)
23         if (str[l1 + i] != str[l2 + i])
24             return false;
25     return true;
26 }
27
28 inline void solve() {
29     f[0][1] = 2000;
30     for (int i = 1; i <= n; i++) {
31         f[i][0] = f[i - 1][0] + 1;
32         f[i][1] = f[i - 1][1] + 1;
33         if (!(i & 1) && (equal(1, (i >> 1) + 1, i >> 1)))
34             f[i][1] = min(f[i][1], f[i >> 1][0] + 1);
35     }
36     printf("%d\n", min(f[n][0], f[n][1]));
37 }
38
39 int main() {
40     init();
41     solve();
42     return 0;
43 }

Problem B

Problem C Matrix Walk

题目大意

  有一个$x\times y$的网格图,但是不知道$x, y$的值。规定$i$行$j$列的格子的标号为$(i - 1)y + j$。

  给定一个长度为$n$的经过的格子序列,规定只能走相邻的格子,且不能走出边界,也不能停留在同一个格子。问是否可能存在一组$x, y$使得路径合法,如果存在,输出这一组。

  找最大的一组相邻的差作为$y$。

  $x$足够大就好了(为什么?因为没影响)。

  然后代进去检验是否合法。

Code

 1 /**
 2  * Codeforces
 3  * Problem#954C
 4  * Accepted
 5  * Time: 61ms
 6  * Memory: 800k
 7  */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11
12 int n;
13 int *ar;
14
15 inline void init() {
16     scanf("%d", &n);
17     ar = new int[(n + 1)];
18     for (int i = 1; i <= n; i++)
19         scanf("%d", ar + i);
20 }
21
22 int mxd = 1;
23 set<int> s;
24 void termin() {
25     puts("NO");
26     exit(0);
27 }
28
29 inline void solve() {
30     for (int i = 1; i < n; i++) {
31         int dif = abs(ar[i + 1] - ar[i]);
32         if (!dif)
33             termin();
34         if (mxd > 1 && dif > 1 && dif != mxd)
35             termin();
36         if (dif > 1)
37             mxd = dif;
38     }
39
40     int ly = ar[1] % mxd;
41     if (!ly) ly = mxd;
42     int lx = (ar[1] - ly) / mxd + 1;
43     for (int i = 2, cx, cy; i <= n; i++) {
44         cy = ar[i] % mxd;
45         if (!cy) cy = mxd;
46         cx = (ar[i] - cy) / mxd + 1;
47         if (abs(cx - lx) + abs(cy - ly) != 1)
48             termin();
49         lx = cx, ly = cy;
50     }
51     puts("YES");
52     printf("%d %d", 1000000000, mxd);
53 }
54
55 int main() {
56     init();
57     solve();
58     return 0;
59 }

Problem C

Problem D Fight Against Traffic

题目大意

  给定$n$个点$m$条边的无向连通简单图。每条边边权均为1。

  要求加一条原本不存在的边,使得新图没有自环,$s, t$之间的距离不改变。

  问方案数。

  看这数据范围挺小的。

  分别跑出$s, t$的最短路径生成树。

  然后枚举边的两个端点,判断加入后新产生的路径长度是否合法。

Code

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef bool boolean;
 4
 5 const int N = 1e3 + 5;
 6
 7 int n, m, s, t;
 8 boolean g[N][N];
 9 int f1[N], f2[N];
10
11 inline void init() {
12     scanf("%d%d%d%d", &n, &m, &s, &t);
13     for (int i = 1, u, v; i <= m; i++) {
14         scanf("%d%d", &u, &v);
15         g[u][v] = true, g[v][u] = true;
16     }
17 }
18
19 typedef class Node {
20     public:
21         int p, dis;
22
23         Node(int p = 0, int dis = 0):p(p), dis(dis) {    }
24
25         boolean operator < (Node b) const {
26             return dis > b.dis;
27         }
28 }Node;
29
30 priority_queue<Node> que;
31 void dijstra(int s, int* f) {
32     memset(f, 0x7f, sizeof(int) * (n + 1));
33     que.push(Node(s, f[s] = 0));
34     while (!que.empty()) {
35         Node e = que.top();
36         que.pop();
37         if (e.dis != f[e.p])
38             continue;
39         for (int i = 1; i <= n; i++)
40             if (g[e.p][i] && e.dis + 1 < f[i])
41                 que.push(Node(i, f[i] = e.dis + 1));
42     }
43 }
44
45 int ans = 0;
46 inline void solve() {
47     dijstra(s, f1);
48     dijstra(t, f2);
49     for (int i = 1; i <= n; i++)
50         for (int j = i + 1; j <= n; j++)
51             if (!g[i][j] && f1[i] + f2[j] + 1 >= f1[t] && f1[j] + f2[i] + 1 >= f1[t])
52                 ans++;
53     printf("%d", ans);
54 }
55
56 int main() {
57     init();
58     solve();
59     return 0;
60 }

Problem D

Problem E Water Taps

题目大意

  给定$n, T, a_{i}, t_{i}$,找出一组$x_{i}$满足$0\leqslant x_{i} \leqslant a_{i}$,且$\frac{\sum_{i = 1}^{n}x_{i}t_{i}}{\sum_{i = 1}^{n}x_{i}} = T$。问$\sum_{i = 1}^{n}x_{i}$的最大值。无解输出0。

  好像一群人直接贪心。表示考场上没想出纯贪心。

  Virtual Contest中看完题,觉得可以用函数搞一搞。

  考虑如果设$D = \sum_{i = 1}^{n}x_{i}$,那么设$f(D), g(D)$分别是$\sum_{i = 1}^{n}x_{i}t_{i}$的最小值和最大值。

  然后猜想$[f(D), g(D)]$之间的一切实数都可以被$\sum_{i = 1}^{n}x_{i}t_{i}$凑出来。

  然后表示智商不够,不会证明。日后会了补上。

  至于$f(D), g(D)$显然可以用贪心来求。画出来的图像大概是这样的:

  当$y = T\times D$被另两函数夹在中间的时候都是合法的。因此我们可以求在第一象限内的两个交点。求出来之后就可以算答案了。

  于是便有了二分答案 + 贪心的做法。然后我也不知道发生了什么:

  然后我改成函数求交:

  有毒。

Code

 1 /**
 2  * Codeforces
 3  * Problem#954E
 4  * Accepted
 5  * Time: 109ms
 6  * Memory: 1600k
 7  */
 8 #include <bits/stdc++.h>
 9 using namespace std;
10 typedef bool boolean;
11
12 const int N = 2e5 + 5;
13
14 typedef class Tap {
15     public:
16         int a, t;
17
18         boolean operator < (Tap b) const {
19             return t < b.t;
20         }
21 }Tap;
22
23 int n, T;
24 Tap ts[N];
25 double s = 0, sT = 0;
26
27 inline void init() {
28     scanf("%d%d", &n, &T);
29     for (int i = 1; i <= n; i++)
30         scanf("%d", &ts[i].a);
31     for (int i = 1; i <= n; i++)
32         scanf("%d", &ts[i].t);
33     for (int i = 1; i <= n; i++) {
34         if (ts[i].t != T)
35             s += ts[i].a;
36         else
37             sT += ts[i].a;
38     }
39 }
40
41 inline void solve() {
42     sort(ts + 1, ts + n + 1);
43
44     if (ts[1].t > T || ts[n].t < T) {
45         puts("0");
46         return;
47     }
48
49     double sm = 0, sa = 0;
50     double l = 0, r = 0;
51     for (int i = 1; i <= n; i++) {
52         if (ts[i].t == T)
53             continue;
54         if ((sa + ts[i].a) * T > sm + ts[i].a * 1ll * ts[i].t)
55             sa += ts[i].a, sm += ts[i].a * 1ll * ts[i].t, l = sa;
56         else {
57             double dis = sa * T - sm;
58             double dx = dis / (ts[i].t - T);
59             l = sa + dx;
60             break;
61         }
62     }
63
64     sm = 0, sa = 0;
65     for (int i = n; i; i--) {
66         if (ts[i].t == T)
67             continue;
68         if ((sa + ts[i].a) * T < sm + ts[i].a * 1ll * ts[i].t)
69             sa += ts[i].a, sm += ts[i].a * 1ll * ts[i].t, r = sa;
70         else {
71             double dis = sa * T - sm;
72             double dx = dis / (ts[i].t - T);
73             r = sa + dx;
74         }
75     }
76
77     printf("%.9lf", min(l, r) + sT);
78 }
79
80 int main() {
81     init();
82     solve();
83     return 0;
84 }

Problem E

Problem F Runner‘s Problem

题目大意

  给定一个$3\times m$的棋盘,在$(2, 1)$的地方有一个棋子,棋子每次只能移动到下一列的相邻的行或者当前行。

  棋盘上有$n$段障碍,第$i$段障碍是在第$a_{i}$行的$l_{i}$列到第$r_{i}$列。棋子不能到障碍格上。

  问棋子从$(2, 1)$到$(2, m)$的方案数。(答案模$10^{9} + 7$)

  随便写写dp方程,把转移表变成矩阵。跑快速幂。

Code

  1 /**
  2  * Codeforces
  3  * Problem#954F
  4  * Accepted
  5  * Time: 390ms
  6  * Memory: 1700k
  7  */
  8 #include <bits/stdc++.h>
  9 #ifndef WIN32
 10 #define Auto "%lld"
 11 #else
 12 #define Auto "%I64d"
 13 #endif
 14 using namespace std;
 15 typedef bool boolean;
 16
 17 #define ll long long
 18 #define pli pair<ll, int>
 19
 20 typedef class Segment {
 21     public:
 22         ll l, r;
 23         int sta;
 24
 25         Segment() {        }
 26         Segment(ll l, ll r, int sta):l(l), r(r), sta(sta) {    }
 27 }Segment;
 28
 29 const int M = 1e9 + 7;
 30
 31 typedef class Matrix {
 32     public:
 33         int r, c;
 34         int a[3][3];
 35
 36         Matrix(int r = 0, int c = 0):r(r), c(c) {}
 37
 38         Matrix operator * (Matrix b) {
 39             Matrix rt(r, b.c);
 40             assert(c == b.r);
 41             for (int i = 0; i < r; i++)
 42                 for (int j = 0; j < b.c; j++) {
 43                     rt[i][j] = 0;
 44                     for (int k = 0; k < c; k++)
 45                         rt[i][j] = (rt[i][j] + a[i][k] * 1ll * b[k][j]) % M;
 46                 }
 47             return rt;
 48         }
 49
 50         int* operator [] (int p) {
 51             return a[p];
 52         }
 53 }Matrix;
 54
 55 const int N = 3e4 + 6;
 56
 57 Matrix qpow(Matrix a, ll p) {
 58     assert(p >= 0);
 59     Matrix pa = a, rt(3, 3);
 60     for (int i = 0; i < 3; i++)
 61         for (int j = 0; j < 3; j++)
 62             rt[i][j] = (i == j);
 63     for ( ; p; p >>= 1, pa = pa * pa)
 64         if (p & 1)
 65             rt = rt * pa;
 66     return rt;
 67 }
 68
 69 int n;
 70 ll m;
 71 pli ad[N], rm[N];
 72 Segment ss[N];
 73
 74 inline void init() {
 75     scanf("%d"Auto, &n, &m);
 76     int a;
 77     ll l, r;
 78     for (int i = 1; i <= n; i++) {
 79         scanf("%d"Auto""Auto, &a, &l, &r);
 80         ad[i].first = l, ad[i].second = a - 1;
 81         rm[i].first = r + 1, rm[i].second = a - 1;
 82     }
 83 }
 84
 85 Matrix mktrans(int os, int ns) {
 86     Matrix rt(3, 3);
 87     for (int i = 0; i < 3; i++)
 88         for (int j = 0; j < 3; j++)
 89             rt[i][j] = (abs(i - j) <= 1 && !(os & (1 << i)) && !(ns & (1 << j)));
 90     return rt;
 91 }
 92
 93 int ts[4], tp = 0;
 94 inline void solve() {
 95     sort(ad + 1, ad + n + 1);
 96     sort(rm + 1, rm + n + 1);
 97     int ca = 1, cb = 1;
 98     ll st = 1, ed;
 99     while (ca <= n || cb <= n) {
100         while (ca <= n && ad[ca].first == st)
101             ts[ad[ca].second]++, ca++;
102         while (cb <= n && rm[cb].first == st)
103             ts[rm[cb].second]--, cb++;
104
105         int sta = 0;
106         for (int i = 0; i < 3; i++)
107             if (ts[i])
108                 sta |= (1 << i);
109
110         ed = m + 1;
111         if (ca <= n)
112             ed = ad[ca].first;
113         if (cb <= n)
114             ed = min(ed, rm[cb].first);
115         ss[++tp] = Segment(st, ed - 1, sta);
116         st = ed;
117     }
118
119     Matrix f(1, 3);
120     f[0][0] = f[0][2] = 0, f[0][1] = 1;
121     Matrix T = mktrans(ss[1].sta, ss[1].sta);
122     f = f * qpow(T, ss[1].r - ss[1].l);
123 //        cerr << f[0][0] << " " << f[0][1] << " " << f[0][2] << endl;
124     for (int i = 2; i <= tp; i++) {
125         T = mktrans(ss[i - 1].sta, ss[i].sta);
126         f = f * T;
127         T = mktrans(ss[i].sta, ss[i].sta);
128         f = f * qpow(T, ss[i].r - ss[i].l);
129 //        cerr << ss[i].l << " " << ss[i].r << endl;
130 //        cerr << f[0][0] << " " << f[0][1] << " " << f[0][2] << endl;
131     }
132     printf("%d\n", f[0][1]);
133 }
134
135 int main() {
136     init();
137     solve();
138     return 0;
139 }

Problem F

Problem G Castle Defense

题目大意

  有片城墙被分为$n$个防守段。第$i$段有$a_{i}$个弓箭手。定义一段防守段的防御力是距离它的距离不超过$r$的所有防守段的弓箭手数量之和。定义这片城墙的稳定程度是每个防守段的防御力的最小值。

  现在有$k$个后备弓箭手,你可将他们分配任何防守段,但不能调动原有的弓箭手。问调动后最大的稳定程度。

  显然二分答案。

  考虑怎么check。对于一个防御值小于$mid$的防守段$i$,能对它产生贡献的一些防守段中分配的后备弓箭手总数不得小于$mid - def[i[$。

  然后设在第$i$个防守段设置的弓箭手数量为$a_{i}$,对它求一个前缀和$s$。

  显然使用差分约束,然后连边就很显然了:

  • $s_{r} - s_{l - 1} \leqslant mid - def[i], (def[i] < mid)$
  • $s[i]\leqslant s[i + 1]$

  由于图比较特殊,不必用最短路算法。直接一个for,完事。

  (感觉把防守段替换为烽火台食用更佳,总之原题说的是section,是在不知道怎么翻译比较好)。

Code

 1 /**
 2  * Codeforces
 3  * Problem#954G
 4  * Accepted
 5  * Time: 358ms
 6  * Memory: 13700k
 7  */
 8 #include <bits/stdc++.h>
 9 #ifndef WIN32
10 #define Auto "%lld"
11 #else
12 #define Auto "%I64d"
13 #endif
14 using namespace std;
15 typedef bool boolean;
16
17 #define ll long long
18
19 const int N = 5e5 + 5;
20
21 int n, r;
22 ll k;
23 int ar[N];
24 ll ps[N], def[N];
25 ll f[N];
26
27 inline void init() {
28     scanf("%d%d"Auto, &n, &r, &k);
29     for (int i = 1; i <= n; i++)
30         scanf("%d", ar + i);
31     for (int i = 1; i <= n; i++)
32         ps[i] = ps[i - 1] + ar[i];
33 }
34
35 boolean check(ll mid) {
36     memset(f, 0, sizeof(f));
37     for (int i = 1; i <= n; i++) {
38         f[i] = max(f[i - 1], f[i]);
39         if (def[i] >= mid)
40             continue;
41         int l = max(i - ::r, 1), r = min(i + ::r, n);
42         f[r] = max(f[l - 1] + mid - def[i], f[r]);
43     }
44     return f[n] <= k;
45 }
46
47 inline void solve() {
48     for (int i = 1; i <= n; i++) {
49         int l = max(i - ::r, 1), r = min(i + ::r, n);
50         def[i] = ps[r] - ps[l - 1];
51     }
52
53     ll l = 0, r = 2e18;
54     while (l <= r) {
55         ll mid = (l + r) >> 1;
56         if (check(mid))
57             l = mid + 1;
58         else
59             r = mid - 1;
60     }
61     printf(Auto, l - 1);
62 }
63
64 int main() {
65     init();
66     solve();
67     return 0;
68 }

Problem G

原文地址:https://www.cnblogs.com/yyf0309/p/9310653.html

时间: 2024-10-07 04:14:49

Educational Codeforces Round 40 (Rated for Div. 2) Partial Solution的相关文章

Educational Codeforces Round 40 (Rated for Div. 2)

这场没打啊 A. Diagonal Walking 签到 B. String Typing 签到 C. Matrix Walk 题意 分析 D. Fight Against Traffic 题意 分析   E. Water Taps 题意 分析 F. Runner's Problem 题意 分析 G. Castle Defense 题意 分析 原文地址:https://www.cnblogs.com/Superwalker/p/8641400.html

Educational Codeforces Round 36 (Rated for Div. 2)

Educational Codeforces Round 36 (Rated for Div. 2) F. Imbalance Value of a Tree You are given a tree T consisting of n vertices. A number is written on each vertex; the number written on vertex i is ai. Let's denote the function I(x,?y) as the differ

Educational Codeforces Round 69 (Rated for Div. 2) B - Pillars

Educational Codeforces Round 69 (Rated for Div. 2) B - Pillars There are n pillars aligned in a row and numbered from 1 to n. Initially each pillar contains exactly one disk. The i-th pillar contains a disk having radius ai. You can move these disks

Educational Codeforces Round 71 (Rated for Div. 2) A - There Are Two Types Of Burgers

原文链接:https://www.cnblogs.com/xwl3109377858/p/11404050.html Educational Codeforces Round 71 (Rated for Div. 2) A - There Are Two Types Of Burgers There are two types of burgers in your restaurant — hamburgers and chicken burgers! To assemble a hamburg

Educational Codeforces Round 71 (Rated for Div. 2) D - Number Of Permutations

原文链接:https://www.cnblogs.com/xwl3109377858/p/11405773.html Educational Codeforces Round 71 (Rated for Div. 2) D - Number Of Permutations You are given a sequence of n pairs of integers: (a1,b1),(a2,b2),…,(an,bn). This sequence is called bad if it is

Educational Codeforces Round 79 (Rated for Div. 2)

A. New Year Garland (CF 1279 A) 题目大意 给定红绿蓝三种颜色灯的数量,问能否摆成一排,使得相邻颜色不相同. 解题思路 植树问题.考虑数量最多为\(n\)的颜色的灯俩俩不相邻,那么其他颜色的灯的数量和要大于\(n-1\)即可,大过\(n-1\)的灯直接插到里面就好了. 神奇的代码 #include <bits/stdc++.h> #define MIN(a,b) ((((a)<(b)?(a):(b)))) #define MAX(a,b) ((((a)>

Educational Codeforces Round 36 (Rated for Div. 2) 题解

Educational Codeforces Round 36 (Rated for Div. 2) 题目的质量很不错(不看题解做不出来,笑 Codeforces 920C 题意 给定一个\(1\)到\(n\)组成的数组,只可以交换某些相邻的位置,问是否可以将数组调整为升序的 解题思路 首先如果每个数都能通过交换到它应该到的位置,那么就可以调整为升序的. 但实际上交换是对称的,如果应该在的位置在当前位置前方的数都交换完成,那么整体就是排好序的,因为不可能所有不在相应位置的数都在相应位置的后方.

Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes

Codeforces Educational Codeforces Round 44 (Rated for Div. 2) E. Pencils and Boxes 题目连接: http://codeforces.com/contest/985/problem/E Description Mishka received a gift of multicolored pencils for his birthday! Unfortunately he lives in a monochrome w

Educational Codeforces Round 55 (Rated for Div. 2)

Educational Codeforces Round 55 (Rated for Div. 2) 链接 A Vasya and Book 傻逼题..注意判边界. #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<set> #include<map> #include<vector> #include<cm