HIT ACM 2018春 week2 codeforces.com/gym/101652 题解

A

题意:判断一个字符串是否存在偶数长度回文子串。

思路:判断是否有两个字符相等即可。O(n)。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 char s[105];
45 int main() {
46     scanf("%s", s + 1);
47     int l = strlen(s + 1);
48     for (int i = 1; i < l; ++i) {
49         if (s[i] == s[i + 1]) {
50             puts("Or not.");
51             return 0;
52         }
53     }
54     puts("Odd.");
55     return 0;
56 }
View Code

B

题意:总共n种字符,判断一个n*n的方格

(1)是否每行都包含n种字符,每一列是否都包含n种字符;

(2)在满足性质(1)的情况下判断第一行和第一列元素是否严格上升

思路:按上述题意模拟即可。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 int n;
45 char s[41][41];
46 set<char> ss;
47 int main() {
48     while (~scanf("%d", &n)) {
49         int flag = 0;
50         for (int i = 1; i <= n; ++i) {
51             scanf("%s", s[i] + 1);
52         }
53         for (int i = 1; i <= n; ++i) {
54             ss.clear();
55             for (int j = 1; j <= n; ++j) {
56                 ss.insert(s[i][j]);
57             }
58             if (n != ss.size()) {
59                 puts("No");
60                 flag = 1;
61                 break;
62             }
63         }
64         if (flag) continue;
65         for (int j = 1; j <= n; ++j) {
66             ss.clear();
67             for (int i = 1; i <= n; ++i) {
68                 ss.insert(s[i][j]);
69             }
70             if (n != ss.size()) {
71                 puts("No");
72                 flag = 1;
73                 break;
74             }
75         }
76         if (flag) continue;
77         for (int i = 2; i <= n; ++i) {
78             if (s[i][1] < s[i - 1][1]) {
79                 puts("Not Reduced");
80                 flag = 1;
81                 break;
82             }
83         }
84         if (flag) continue;
85         for (int j = 2; j <= n; ++j) {
86             if (s[1][j] < s[1][j - 1]) {
87                 puts("Not Reduced");
88                 flag = 1;
89                 break;
90             }
91         }
92         if (flag) continue;
93         puts("Reduced");
94     }
95     return 0;
96 }
View Code

C

题意:定义f(x)为x的约数个数,求SUM(f(x))  (a <= x <= b)

思路:枚举小于等于1e6的因子,对于每一个因子y, a 到 b之间能整出y的个数为 b/y(向下取整) - a/y(向上取整)+ 1,a 到 b 之间能整除y之后剩的因子为 b/y(向下取整), ..., a/y(向上取整)的公差为-1的等差数列。

因此,在最终答案中直接加上y的个数 * y 以及除y后剩的因子和即可。但为了保证每个y只被算一次,我们应该让除y后剩余间的左端点l = max(a/y(向上取整), y)。同时,在y == l时,不要加两次y。计算量为1e6.

没理解的话可以结合代码思考,感觉代码比文字表达更清晰。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 ll a, b, ans;
45 int main() {
46     scanf("%lld%lld", &a, &b);
47     for (ll i = 1; i <= 1000000; ++i) {
48         ll x1 = (a - 1) / i + 1;
49         ll x2 = b / i;
50         if (x1 < i) x1 = i;
51         //printf("%lld %lld %lld
", i, x1, x2);
52         if (i > b) break;
53         if (x1 > x2) continue;
54         if (x1 == i) ans -= x1;
55         ans += (x2 - x1 + 1) * i;
56         ans += (x2 - x1 + 1) * (x2 + x1) >> 1;
57     }
58     printf("%lld", ans);
59     return 0;
60 }
View Code

D

题意:定义一个序列 1, 1, 1, 1, 1, 1, ..., 2, 2, 2, 2, 2, 2, .....i, i, i, i, i,  ..., n - 1 (每个数i连续出现n - i次), 求序列中间的那个数。

思路:对于每个数i,第一次出现的位置都可以O(1)求出来(等差数列求和),我们又可以求出序列总元素个数以及中间数的位置,因此二分判定就好了。O(logn)。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 ll n;
45 ll cal(ll x) {
46     return (n + n - 1 - x) * x >> 1;
47 }
48 int main() {
49     scanf("%lld", &n);
50     ll cnt = ((n * (n - 1) >> 1) + 1) >> 1;
51     ll ans = 0, s = 0, e = n, mi;
52     while (s <= e) {
53         mi = s + e >> 1;
54         if (cal(mi) < cnt) {
55             s = (ans = mi) + 1;
56         } else {
57             e = mi - 1;
58         }
59     }
60     printf("%lld", ans + 1);
61     return 0;
62 }
View Code

E

题意:已知一个机器人的速度,起点终点都在x轴方向,中间有一些竖向的传送带,各个速度都已知, 判定一下机器人到终点的最短时间。

思路:对y轴移动距离列方程,把机器人速度分解,vy * L / vx = SUM(vi * li / vx)。vx可以约掉。因此马上求出vy, vx也可以求出。复杂度O(n)。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 int n;
45 double x, V, v[105], l[105], r[105];
46 int main() {
47     double cnt = 0;
48     scanf("%d%lf%lf", &n, &x, &V);
49     for (int i = 1; i <= n; ++i) {
50         scanf("%lf%lf%lf", &l[i], &r[i], &v[i]);
51         cnt += (r[i] - l[i]) * v[i];
52     }
53     double vy = fabs(cnt / x);
54     if (vy >= V) {
55         puts("Too hard");
56         return 0;
57     } else {
58         double vx = sqrt(V * V - vy * vy);
59         if (vx * 2 <= V + EPS) {
60             puts("Too hard");
61         } else {
62             printf("%.3f
", x / vx);
63         }
64     }
65     return 0;
66 }
View Code

F

题意:对于一个只有RB两种字符的字符串,求出一个子串使得‘R’, ‘B’两种字符数量的差值最大。

思路:可以将问题拆开。一种是求R的数量-B的数量最多,另一个是B的数量-R的数量最大。考虑每个单独的问题,比如要求R-B尽可能多,我们线性扫一遍,如果当前R的数量大于等于B,那么我们遇见R就加1, 遇见B就减1。

如果R比B少,那么我们为了使这个差值尽可能大,显然要舍弃之前选的那段序列,而从当前位置重新开始取。复杂度O(n)。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 int n;
45 char s[100015];
46 void solve(int &ma, int &l1, int &r1, char c) {
47     for (int i = 1, j = 1, cnt = 0, flag = 1; j <= n; ++j) {
48         if (!cnt) {
49             if (c == s[j]) {
50                 ++cnt;
51                 if (cnt > ma) {
52                     l1 = r1 = j;
53                     ma = cnt;
54                 }
55                 if (flag) {
56                     i = j;
57                     flag = 0;
58                 }
59             } else {
60                 flag = 1;
61                 continue;
62             }
63         } else {
64             if (c == s[j]) {
65                 ++cnt;
66                 if (cnt > ma) {
67                     r1 = j;
68                     l1 = i;
69                     ma = cnt;
70                 }
71             } else {
72                 --cnt;
73             }
74         }
75     }
76 }
77 int main() {
78     scanf("%s", s + 1);
79     n = strlen(s + 1);
80     int ma1 = 0, l1 = 0, r1 = 0, ma2 = 0, l2 = 0, r2 = 0;
81     solve(ma1, l1, r1, 'B');
82     solve(ma2, l2, r2, 'R');
83     int ans_l, ans_r;
84     if (ma1 > ma2 || (ma1 == ma2 && (l1 < l2 || (l1 == l2 && r1 < r2)))) {
85         ans_l = l1, ans_r = r1;
86     } else {
87         ans_l = l2, ans_r = r2;
88     }
89     printf("%d %d", ans_l, ans_r);
90     return 0;
91 }
View Code

G

题意:一个有向图中每条边都有一段区间,表示权限,只有x在这段区间内才可以经过这条边,求出所有能从起点走到终点的x。

思路:我们把所有的区间统一改成左闭右开的形式。把所有的时间段的端点提取出来并从小到大排序。然后考虑每个时间点ti,如果ti能从起点到达终点,那么[t(i), t(i + 1))这段区间内的所有时间点都可以到达终点,因为如果t(i)可以到达终点,那么它肯定不能只是一个时间段的右开端点,所以他至少是一个左闭端点,因此其向后取的那一小段时间段一定可取;如果t(i)不能到达,则显然只是一个右开端点,因此不取它后面的一段区间。O(mlogm + m*(m + n))。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 int n, m, k, s, t, ans;
45 struct edge {
46     int v, l, r;
47     edge () {}
48     edge (int v, int l, int r) : v(v), l(l), r(r) {}
49 };
50 vector<edge> E[1015];
51 vector<int> timestamps;
52 bool visit[1015];
53 void dfs(int x, int timestamp) {
54     visit[x] = true;
55     for (int i = 0; i < E[x].size(); ++i) {
56         int v = E[x][i].v;
57         int l = E[x][i].l;
58         int r = E[x][i].r;
59         if (l <= timestamp && timestamp <= r && !visit[v]) {
60             dfs(v, timestamp);
61         }
62     }
63 }
64 int main() {
65     scanf("%d%d%d%d%d", &n, &m, &k, &s, &t);
66     while (m--) {
67         int a, b, c, d;
68         scanf("%d%d%d%d", &a, &b, &c, &d);
69         E[a].pb(edge(b, c, d));
70         timestamps.pb(c);
71         timestamps.pb(d + 1);
72     }
73     sort(timestamps.begin(), timestamps.end());
74     int number_Of_Timestamps = unique(timestamps.begin(), timestamps.end()) - timestamps.begin();
75     for (int i = 0; i < number_Of_Timestamps - 1; ++i) {
76         int timestamp = timestamps[i];
77         clr(visit, false);
78         dfs(s, timestamp);
79         if (visit[t]) {
80             ans += timestamps[i + 1] - timestamps[i];
81         }
82     }
83     printf("%d", ans);
84     return 0;
85 }
View Code

H

题意:改变一个不均匀骰子的一个面的点数(可以为实数),使得其期望为3.5

思路:求出期望差值,除以概率最大的那个面就是改变的最小值。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 double p[11], sum, ma;
45 int main() {
46     for (int i = 1; i <= 6; ++i) {
47         scanf("%lf", &p[i]);
48         sum += p[i] * i;
49         ma = max(ma, p[i]);
50     }
51     printf("%.3f", fabs(sum - 3.5) / ma);
52     return 0;
53 }
View Code

I

题意:一个无限长字符串上一系列插入删除操作,问两组操作是否等价。

思路:用个链表暴力n*n模拟?(这题我还没写,这几天写完更新)

UPDATE:

思路一:

  确实是个链表模拟的n * n暴力,但比较麻烦。我的做法是链表上每个节点存一下到下一个节点的距离(距离定义为当前节点到下一个节点的左开右闭区间内字符个数),以及节点的虚实信息(虚节点定义为存在于最初串中并在之后被删除的元素,即遇见此类删除最初元素的情况,我们在链表中加入一个虚节点;实节点定义为之后插入的新元素;如果插入且之后被删除则我们不存储这类节点,在其被删除的时候也将该实节点从链表中删除)。至此,链表插入删除维护完毕。

  但这样处理会产生问题,即等价的一系列操作会产生不同形式的最终链表(例子在代码最后的注释里)。因此我们在判断之前要对其进行统一化处理,格式之所以不统一是因为有一些地方可以合并但没有合并,所以我们合并所有能合并的地方(再次声明距离的定义是左开右闭区间内字符数量):(1)当前节点为虚节点,且距离下一节点为0,显然可以删掉(2)当前节点为实节点,且前一个节点为虚节点且距当前节点距离1,此时我们应删除前一个节点,并让新产生的前一个节点距离加1(3)其他所有情况都代表着两个节点之间有原序列中的元素,皆不可合并。

  最后严格地判断两个链表中对应节点是否完全相等即可。

  1 #include <iostream>
  2 #include <fstream>
  3 #include <sstream>
  4 #include <cstdlib>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <string>
  8 #include <cstring>
  9 #include <algorithm>
 10 #include <queue>
 11 #include <stack>
 12 #include <vector>
 13 #include <set>
 14 #include <map>
 15 #include <list>
 16 #include <iomanip>
 17 #include <cctype>
 18 #include <cassert>
 19 #include <bitset>
 20 #include <ctime>
 21 
 22 using namespace std;
 23 
 24 #define pau system("pause")
 25 #define ll long long
 26 #define pii pair<int, int>
 27 #define pb push_back
 28 #define mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30 
 31 const double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const double EPS = 1e-9;
 35 
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39 
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43 
 44 struct node {
 45     ll l;
 46     bool is_real;
 47     char c;
 48     node () {}
 49     node (ll l, bool is_real, char c) : l(l), is_real(is_real), c(c) {}
 50     bool operator != (const node &tnode) const {
 51         return l != tnode.l || is_real != tnode.is_real || c != tnode.c;}
 52 };
 53 list<node> l1, l2;
 54 void ini() {
 55     l1.insert(l1.begin(), node(1e17, true, '#'));
 56     l1.insert(l1.end(), node(1e17, true, '#'));
 57     l2.insert(l2.begin(), node(1e17, true, '#'));
 58     l2.insert(l2.end(), node(1e17, true, '#'));
 59 }
 60 void Insert(list<node> &l) {
 61     ll p;
 62     char c;
 63     scanf("%lld %c", &p, &c);
 64     list<node>::iterator it = l.begin();
 65     ll cnt = 0;
 66     while (it != l.end()) {
 67         if (p > cnt + (*it).l) {
 68             cnt += (*it).l;
 69             ++it;
 70         } else {
 71             ll len = (*it).l;
 72             (*it).l = p - cnt;
 73             l.insert(++it, node(len + 1 - (p - cnt), true, c));
 74             break;
 75         }
 76     }
 77     /*for (list<node>::iterator it = l.begin(); it != l.end(); ++it) {
 78         printf("len1 = %lld, is_real1 = %d, c1 = %c
", (*it).l, (*it).is_real, (*it).c);
 79     }*/
 80 }
 81 void Delete(list<node> &l) {
 82     ll p;
 83     scanf("%lld", &p);
 84     list<node>::iterator it = l.begin();
 85     ll cnt = 0;
 86     while (it != l.end()) {
 87         if (p > cnt + (*it).l) {
 88             cnt += (*it).l;
 89             ++it;
 90         } else {
 91             ll len = (*it).l;
 92             (*it).l = p - cnt - 1;
 93             list<node>::iterator it1 = ++it;
 94             --it;
 95 
 96             if (l.end() == it1 || p < cnt + len || (p == cnt + len && !(*it1).is_real)) {
 97                 l.insert(it1, node(len - (p - cnt), false, '#'));
 98             } else {
 99                 ll len2 = (*it1).l;
100                 (*it).l += len2;
101                 l.erase(it1);
102             }
103             break;
104         }
105     }
106     /*for (list<node>::iterator it = l.begin(); it != l.end(); ++it) {
107         printf("len1 = %lld, is_real1 = %d, c1 = %c
", (*it).l, (*it).is_real, (*it).c);
108     }*/
109 }
110 void modify(list<node> &l) {
111     for (list<node>::iterator it = l.begin(); it != l.end(); ) {
112         if (0 == (*it).l && !(*it).is_real) {
113             it = l.erase(it);
114         } else {
115             if ((*it).is_real) {
116                 list<node>::iterator it1 = it;
117                 --it1;
118                 if (1 == (*it1).l && !(*it1).is_real) {
119                     it1 = l.erase(it1);
120                     --it1;
121                     ++(*it1).l;
122                 }
123             }
124             ++it;
125         }
126     }
127 }
128 bool Equal() {
129 
130     modify(l1);
131     modify(l2);
132 
133     if (l1.size() != l2.size()) return false;
134 
135     list<node>::iterator it1 = l1.begin();
136     list<node>::iterator it2 = l2.begin();
137 
138     for (; it1 != l1.end() && it2 != l2.end(); ) {
139         //printf("len1 = %lld, is_real1 = %d, c1 = %c
", (*it1).l, (*it1).is_real, (*it1).c);
140         //printf("len2 = %lld, is_real2 = %d, c2 = %c
", (*it2).l, (*it2).is_real, (*it2).c);
141 
142         if (*it1 != *it2) return false;
143 
144         ++it1, ++it2;
145     }
146 
147     return true;;
148 }
149 void solve(list<node> &l) {
150     char op;
151     while (scanf(" %c", &op) && 'E' != op) {
152         if ('I' == op) {
153             Insert(l);
154         } else {
155             Delete(l);
156         }
157     }
158 }
159 int main() {
160     ini();
161     solve(l1);
162     solve(l2);
163     puts(Equal() ? "0" : "1");
164     return 0;
165 }
166 /*
167 I 3 x
168 D 5
169 D 4
170 D 2
171 D 1
172 E
173 I 1 x
174 D 2
175 D 2
176 D 2
177 D 2
178 E
179 */
View Code

思路二:

官方题解的做法,就是不用链表模拟,将所有的操作都统一成D i1, i2, ..., in, I j1, j2, ..., jm 的形式,其中i序列递减,j序列递增。类似冒泡排序按五类情况模拟即可。

J

题意:一个n * m的方格上有‘B’, 'R', '.'分别表示黑色,红色,以及目前为空着。要求每个B左上角的所有块都必须为黑色,R右下角的所有块都必须为红色。

思路:你可以先n*n*m*m暴力利用所有已知的R,B信息把方格填充,这样左上角以及右下角都被确定,待处理的只有中间空的一部分,这个中间部分满足列数从左到右时,其相应待确定的行数单调递减。

因此,我们用dp[j][i]表示第j列第i行为此列最后一个黑色块,那么dp[j][i] = SUM(dp[j - 1][k]),其中k从i到n。复杂度O(n * n * m * m),可以优化到O(n*m)。

  1 #include <iostream>
  2 #include <fstream>
  3 #include <sstream>
  4 #include <cstdlib>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <string>
  8 #include <cstring>
  9 #include <algorithm>
 10 #include <queue>
 11 #include <stack>
 12 #include <vector>
 13 #include <set>
 14 #include <map>
 15 #include <list>
 16 #include <iomanip>
 17 #include <cctype>
 18 #include <cassert>
 19 #include <bitset>
 20 #include <ctime>
 21 
 22 using namespace std;
 23 
 24 #define pau system("pause")
 25 #define ll long long
 26 #define pii pair<int, int>
 27 #define pb push_back
 28 #define mp make_pair
 29 #define clr(a, x) memset(a, x, sizeof(a))
 30 
 31 const double pi = acos(-1.0);
 32 const int INF = 0x3f3f3f3f;
 33 const int MOD = 1e9 + 7;
 34 const double EPS = 1e-9;
 35 
 36 /*
 37 #include <ext/pb_ds/assoc_container.hpp>
 38 #include <ext/pb_ds/tree_policy.hpp>
 39 
 40 using namespace __gnu_pbds;
 41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
 42 */
 43 
 44 int n, m;
 45 char mmp[35][35];
 46 ll dp[35][35];
 47 
 48 int main() {
 49     scanf("%d%d", &n, &m);
 50     for (int i = 1; i <= n; ++i) {
 51         scanf("%s", mmp[i] + 1);
 52     }
 53     for (int i = 1; i <= n; ++i) {
 54         for (int j = 1; j <= m; ++j) {
 55             if ('B' == mmp[i][j]) {
 56                 for (int k = 1; k <= i; ++k) {
 57                     for (int l = 1; l <= j; ++l) {
 58                         if ('R' == mmp[k][l]) {
 59                             puts("0");
 60                             return 0;
 61                         }
 62                         mmp[k][l] = 'B';
 63                     }
 64                 }
 65             }
 66             if ('R' == mmp[i][j]) {
 67                 for (int k = i; k <= n; ++k) {
 68                     for (int l = j; l <= m; ++l) {
 69                         if ('B' == mmp[k][l]) {
 70                             puts("0");
 71                             return 0;
 72                         }
 73                         mmp[k][l] = 'R';
 74                     }
 75                 }
 76             }
 77         }
 78     }
 79     for (int i = n; ~i; --i) {
 80         if ('R' == mmp[i][1]) continue;
 81         dp[i][1] = 1;
 82         if ('B' == mmp[i][1]) break;
 83     }
 84     for (int j = 2; j <= m; ++j) {
 85         for (int i = n; ~i; --i) {
 86             if ('R' == mmp[i][j]) continue;
 87             for (int k = i; k <= n; ++k) {
 88                 dp[i][j] += dp[k][j - 1];
 89             }
 90             if ('B' == mmp[i][j]) break;
 91         }
 92     }
 93     /*for (int i = 0; i <= n; ++i) {
 94         for (int j = 1; j <= m; ++j) {
 95             printf("%d ", dp[i][j]);
 96         }
 97         puts("");
 98     }*/
 99     ll ans = 0;
100     for (int i = 0; i <= n; ++i) {
101         ans += dp[i][m];
102     }
103     printf("%lld", ans);
104     return 0;
105 }
View Code

K

题意:美国国旗是有s个星,所有奇数行星数都为x, 所有偶数行星数都为y, x等于y或y + 1。

思路:枚举三种情况,(1) x == y (2) x == y + 1总行数为偶数 (3) x == y + 1总行数为奇数。最后排下序,复杂度O(S + sqrt(s) * logs)。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 set<pii> ss;
45 int s;
46 int main() {
47     scanf("%d", &s);
48     for (int i = 2; i < s; ++i) {
49         if (s % i == 0) {
50             ss.insert(mp(i, i));
51         }
52     }
53     for (int i = 2; i < s; ++i) {
54         if ((s - i) % (i + i - 1) == 0 || (s % (i + i - 1) == 0) ) {
55             ss.insert(mp(i, i - 1));
56         }
57     }
58     printf("%d:
", s);
59     for (set<pii>::iterator it = ss.begin(); it != ss.end(); ++it) {
60         int x = (*it).first, y = (*it).second;
61         printf("%d,%d
", x, y);
62     }
63     return 0;
64 }
View Code

L

题意:已知x, k, p, 求x * n + k * p / n的最小值

思路:对号函数,因为n为整数,输出sqrt(k * p / x)左右两个整点对应函数值的最小值。O(1)。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 int k, p, x;
45 double cal(int n) {
46     return 1.0 * x * n + 1.0 * k * p / n;
47 }
48 int main() {
49     scanf("%d%d%d", &k, &p, &x);
50     int n = sqrt((k * p + 0.5) / x);
51     printf("%.3f
", min(cal(n), cal(n + 1)));
52     return 0;
53 }
View Code

M

题意:给一个n,求出大于n中第一个不含0的数。

思路:从n+1开始枚举即可,复杂度O(n / 10)。

 1 #include <iostream>
 2 #include <fstream>
 3 #include <sstream>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <cmath>
 7 #include <string>
 8 #include <cstring>
 9 #include <algorithm>
10 #include <queue>
11 #include <stack>
12 #include <vector>
13 #include <set>
14 #include <map>
15 #include <list>
16 #include <iomanip>
17 #include <cctype>
18 #include <cassert>
19 #include <bitset>
20 #include <ctime>
21 
22 using namespace std;
23 
24 #define pau system("pause")
25 #define ll long long
26 #define pii pair<int, int>
27 #define pb push_back
28 #define mp make_pair
29 #define clr(a, x) memset(a, x, sizeof(a))
30 
31 const double pi = acos(-1.0);
32 const int INF = 0x3f3f3f3f;
33 const int MOD = 1e9 + 7;
34 const double EPS = 1e-9;
35 
36 /*
37 #include <ext/pb_ds/assoc_container.hpp>
38 #include <ext/pb_ds/tree_policy.hpp>
39 
40 using namespace __gnu_pbds;
41 tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> T;
42 */
43 
44 int n;
45 bool ok(int x) {
46     while (x) {
47         if (x % 10 == 0) return false;
48         x /= 10;
49     }
50     return true;
51 }
52 int main() {
53     scanf("%d", &n);
54     for (int i = n + 1; ; ++i) {
55         if (ok(i)) {
56             printf("%d
", i);
57             return 0;
58         }
59     }
60 
61     return 0;
62 }
View Code
原文地址:https://www.cnblogs.com/BIGTOM/p/8544267.html