题目
题目评级
A = B < C < E < F = D
F虽说是折半搜索板子可以 但是卡常卡了70 70 7 0 min 5 5 5 发才过的我 因为我们忘记把map换成unorderedmap
A.ABC -> AC
题目描述
给你一个由大写英文字母组成的字符串 S S S 。这里, S S S 的长度是奇数。
打印删除 S S S 中间字符后得到的字符串。 S S S 的中间字符是 S S S 的 L + 1 2 \frac{L+1}{2} 2 L + 1 -th 字符,其中 L L L 是 S S S 的长度。
思路
语法题 所以就做完了
代码
1 2 3 4 5 6 7 8 9 10 11 #include <bits/stdc++.h> using namespace std;#define int long long signed main () { string s; cin >> s; s.erase ((s.length ()) / 2 , 1 ); cout << s; return 0 ; }
B.Sum of Digits Sequence
题目描述
对于正整数 N N N ,把 f ( x ) f(x) f ( x ) 定义为 x x x 的十进制表示中的数位之和。例如, f ( 123 ) = 1 + 2 + 3 = 6 f(123) = 1 + 2 + 3 = 6 f ( 1 2 3 ) = 1 + 2 + 3 = 6 。
用下面的公式定义一个无穷序列 A = ( A 0 , A 1 , A 2 , … ) A = (A_0, A_1, A_2, \ldots) A = ( A 0 , A 1 , A 2 , … ) :
A 0 = 1 A_0 = 1 A 0 = 1
对于 i ≥ 1 i \geq 1 i ≥ 1 , A i = ∑ j = 0 i − 1 f ( A j ) A_i = \displaystyle\sum_{j = 0}^{i - 1} f(A_j) A i = j = 0 ∑ i − 1 f ( A j )
给你一个正整数 N N N 。求 A N A_N A N 的值。
思路
语法题 所以就做完了
代码
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 #include <bits/stdc++.h> using namespace std;#define int long long int calc (int n) { int res = 0 ; while (n) { res += n % 10 ; n /= 10 ; } return res; } signed main () { int n; cin >> n; vector<int > a (n + 1 ) , f (n + 1 ) ; a[0 ] = 1 ; f[0 ] = calc (a[0 ]); for (int i = 1 ; i <= n; i++) { a[i] = 0 ; for (int j = 0 ; j < i; j++) { a[i] += f[j]; } if (i < n + 1 ) { f[i] = calc (a[i]); } } cout << a[n]; return 0 ; }
C.Bipartize
题目描述
问题陈述
有一个简单的无向图,该图有 N N N 个顶点和 M M M 条边。该图由顶点 1 , 1, 1 , 顶点 2 , … , 2,\ldots, 2 , … , 顶点 N N N 和连接顶点 u i u _ i u i 和 v i v _ i v i 的 i i i -th 边 ( 1 ≤ i ≤ M ) (1\le i\le M) ( 1 ≤ i ≤ M ) 组成。
您将执行以下操作零次或多次:
以最少的操作让原图变成二分图
思路
状压其实很显然 因为n ≤ 10 n \leq 10 n ≤ 1 0 。
那我们直接大力状压枚举状态,然后每次发现一条边两边的点在同一集合里,你就更新答案,就做完了。
代码
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 #include <bits/stdc++.h> using namespace std;#define int long long signed main () { int n, m; cin >> n >> m; vector<pair<int , int >> edges (m); for (int i = 0 ; i < m; i++) { cin >> edges[i].first >> edges[i].second; edges[i].first--; edges[i].second--; } int ans = m; for (int i = 0 ; i < (1 << n); i++) { int cnt = 0 ; for (int j = 0 ; j < m; j++) { if (((i >> edges[j].first) & 1 ) == ((i >> edges[j].second) & 1 )) { cnt++; } } ans = min (ans, cnt); } cout << ans; return 0 ; }
D.The Simple Game
题目描述
有一个有向图,图中有 N N N 个顶点和 M M M 条边。顶点的编号从 1 1 1 到 N N N , i i i 条边是从顶点 U i U_i U i 到顶点 V i V_i V i 的有向边。在这里,每个顶点的出度至少为 1 1 1 。
此外,每个顶点上都有一个字符,顶点 i i i 上的字符是 S i S_i S i 。这里, S i S_i S i 指的是 S S S 的 i i i 个字符。
爱丽丝和鲍勃用一个棋子在这个图上玩下面的游戏:
求双方都以最优方式下棋时的胜者。
在每个输入中,你都会得到 T T T 个测试用例。求解每个案例。
思路
不知道为什么 但是数据范围告诉你也许能记忆化
我们直接倒着推,然后到倒着推的同时大力DFS然后它就过了,我们对每个状态,看一下与它相连的边,如果往那条边搜发现自己能赢,那这个人的策略就是往这条边移动
然后操作次数是2 ∗ k 2*k 2 ∗ k ,别搞错了(
代码
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 #include <bits/stdc++.h> using namespace std;int n, m, k;string s; vector<int > edges[200005 ]; vector<vector<vector<int >>> ans; bool dfs (int x, int y, bool flag) { if (y == 0 ) { return s[x - 1 ] == 'A' ; } if (ans[x][y][flag] != -1 ) { return ans[x][y][flag]; } if (flag) { bool anss = 0 ; for (int nex : edges[x]) { if (dfs (nex, y - 1 , 0 )) { anss = 1 ; break ; } } return ans[x][y][flag] = anss; } else { bool anss = 1 ; for (int nex : edges[x]) { if (!dfs (nex, y - 1 , 1 )) { anss = 0 ; break ; } } return ans[x][y][flag] = anss; } } void solve () { cin >> n >> m >> k; cin >> s; for (int i = 1 ; i <= n; i++) { edges[i].clear (); } for (int i = 0 ; i < m; i++) { int u, v; cin >> u >> v; edges[u].push_back (v); } ans.assign (n + 1 , vector<vector<int >>(2 * k + 1 , vector <int >(2 , -1 ))); cout << (dfs (1 , 2 * k, 1 ) ? "Alice" : "Bob" ) << '\n' ; } signed main () { int T; cin >> T; while (T--) { solve (); } return 0 ; }
E.Wind Cleaning
题目描述
有一个网格,网格中有 H H H 行和 W W W 列。让 ( i , j ) (i, j) ( i , j ) 表示从上往下第 i i i 行和从左往上第 j j j 列的单元格。
高桥就在这个网格中的一个单元格上,而网格中的一些单元格上有垃圾。
单元格的状态由长度为 W W W 的 H H H 字符串 S 1 , S 2 , … , S H S_1, S_2, \ldots, S_H S 1 , S 2 , … , S H 给出,其中 S i , j S_{i, j} S i , j 表示 S i S_i S i 的 j j j -th 字符,代表以下状态:
如果 S i , j = S_{i, j} = S i , j = T
, 则( i , j ) (i, j) ( i , j ) 单元格就是高桥所在的单元格。
如果是 S i , j = S_{i, j} = S i , j = #
,则( i , j ) (i, j) ( i , j ) 单元格是高桥所在的单元格。#`, ( i , j ) (i, j) ( i , j ) 单元格就是有垃圾的单元格。
如果是 S i , j = S_{i, j} = S i , j = .
,则( i , j ) (i, j) ( i , j ) 单元格是没有垃圾的空格。
高桥所在的单元格没有垃圾。
他可以重复执行以下操作:
从四个方向(上、下、左、右)中选择一个,同时将所有垃圾向该方向移动一格。在这里,如果垃圾移动到格子外,垃圾就会消失;如果垃圾移动到他所在的格子,他就会变脏。
请判断他是否有可能在不弄脏的情况下让所有垃圾消失,如果可能,请找出尽可能少的操作次数。
思路
结论:暴力全对 直接BFS就做完了
对啊 你直接那个set记一下哪些地方有垃圾,然后直接暴力转移 1发就过了 所以不知道为什么你们不做(
我们知道每个垃圾每次挪就1 1 1 格,不难发现横向纵向的移动根本不会超过二倍边长,然后能得到的状态其实很少,然后这题BFS最多4 ∗ H ∗ W 4 * H * W 4 ∗ H ∗ W 轮 然后时间复杂度就完全正确了(
代码
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 #include <bits/stdc++.h> using namespace std;#define int long long signed main () { int n, m; cin >> n >> m; vector<string> a (n) ; int tx, ty; for (int i = 0 ; i < n; i++) { cin >> a[i]; for (int j = 0 ; j < m; j++) { if (a[i][j] == 'T' ) { tx = i; ty = j; } } } set<pair<int , int >> init; for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < m; j++) { if (a[i][j] == '#' ) { init.insert ({i, j}); } } } queue<set<pair<int , int >>> q; set<set<pair<int , int >>> st; q.push (init); st.insert (init); int ans = 0 ; vector<pair<int , int >> dir = {{-1 , 0 }, {1 , 0 }, {0 , -1 }, {0 , 1 }}; while (!q.empty ()) { int sz = q.size (); for (int i = 0 ; i < sz; i++) { set<pair<int , int >> tp = q.front (); q.pop (); if (tp.empty ()) { cout << ans; return 0 ; } for (auto &d : dir) { set<pair<int , int >> tpst; bool flag = 0 ; for (auto &j : tp) { int dx = j.first + d.first; int dy = j.second + d.second; if (dx >= 0 && dx < n && dy >= 0 && dy < m) { if (dx == tx && dy == ty) { flag = 1 ; break ; } tpst.insert ({dx, dy}); } } if (!flag && st.find (tpst) == st.end ()) { st.insert (tpst); q.push (tpst); } } } ans++; } cout << -1 ; return 0 ; }
F.Not Adjacent
题目描述
给你一个长度为 N N N 的整数序列 A = ( A 1 , A 2 , … , A N ) A=(A _ 1,A _ 2,\ldots,A _ N) A = ( A 1 , A 2 , … , A N ) 。
有 2 N 2 ^ N 2 N 个(不一定连续)的子序列 A A A 。求有多少个子序列 ( A i 1 , A i 2 , … , A i k ) ( 1 ≤ i 1 < i 2 < ⋯ < i k ≤ N ) (A _ {i _ 1},A _ {i _ 2},\ldots,A _ {i _ k})\ (1\le i _ 1\lt i _ 2\lt\cdots\lt i _ k\le N) ( A i 1 , A i 2 , … , A i k ) ( 1 ≤ i 1 < i 2 < ⋯ < i k ≤ N ) 同时满足以下两个条件:
所选元素在 A A A 中不相邻。也就是说, 1 + i j ≠ i j + 1 1+i _ j\ne i _ {j+1} 1 + i j = i j + 1 对所有 1 ≤ j < k 1\le j\lt k 1 ≤ j < k 都成立。
和是 M M M 的倍数。即 ∑ j = 1 k A i j ≡ 0 ( m o d M ) \displaystyle\sum _ {j=1} ^ kA _ {i _ j}\equiv0\pmod M j = 1 ∑ k A i j ≡ 0 ( m o d M ) 。
即使两个子序列作为整数序列是相等的,但如果它们所处的位置不同,也要分别计算。
思路
直接大力折半搜索 O ( 2 n 2 ) O(2^{\frac{n}{2}}) O ( 2 2 n ) 然后像我一样卡常卡1个多小时就过了:
代码
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 #include <bits/stdc++.h> using namespace std;#define int long long int m;void dfs (int x, int cnt, int ls, int f, const vector<int > &v, int st, bool flag, vector<pair<int , int >> &res) { if (x == v.size ()) { if (flag && f != 0 ) { res.push_back ({f, cnt}); } else if (!flag && ls != 0 ) { res.push_back ({ls, cnt}); } return ; } dfs (x + 1 , cnt, ls, f, v, st, flag, res); int pos = x + st; if (ls == 0 || pos >= ls + 2 ) { int tpsum = (cnt + v[x]) % m; int tpls = pos; int tpf = flag && (f == 0 ) ? pos : f; dfs (x + 1 , tpsum, tpls, tpf, v, st, flag, res); } } signed main () { ios::sync_with_stdio (0 ); cin.tie (0 ); int n; cin >> n >> m; vector<int > a (n) ; for (int i = 0 ; i < n; i++) { cin >> a[i]; } int mid = n / 2 ; vector<int > v1 (a.begin(), a.begin() + mid) ; vector<int > v2 (a.begin() + mid, a.end()) ; vector<pair<int , int >> s1; s1. reserve (1 << 22 ); vector<pair<int , int >> s2; s2. reserve (1 << 22 ); if (!v1. empty ()) { dfs (0 , 0 , 0 , 0 , v1, 1 , false , s1); } if (!v2. empty ()) { dfs (0 , 0 , 0 , 0 , v2, mid + 1 , true , s2); } sort (s1. begin (), s1. end ()); vector<pair<pair<int , int >, int >> mp1; for (int i = 0 ; i < s1. size (); i++) { if (i == 0 || s1[i] != s1[i - 1 ]) { mp1. push_back ({s1[i], 1 }); } else { mp1. back ().second++; } } sort (s2. begin (), s2. end ()); vector<pair<pair<int , int >, int >> mp2; for (int i = 0 ; i < s2. size (); i++) { if (i == 0 || s2[i] != s2[i - 1 ]) { mp2. push_back ({s2[i], 1 }); } else { mp2. back ().second++; } } int ans = 0 ; for (auto &[k, cnt] : mp1) { if (k.second == 0 ) { ans += cnt; } } for (auto &[k, cnt] : mp2) { if (k.second == 0 ) { ans += cnt; } } map<int , vector<pair<int , int >>> mp3; for (auto &[k, cnt] : mp2) { mp3[k.second].push_back ({k.first, cnt}); } map<int , vector<pair<int , int >>> mp4; for (auto &[x, v] : mp3) { sort (v.begin (), v.end ()); vector<pair<int , int >> tp; int cnt = 0 ; for (int i = (int )v.size () - 1 ; i >= 0 ; i--) { cnt += v[i].second; tp.push_back ({v[i].first, cnt}); } reverse (tp.begin (), tp.end ()); mp4[x] = tp; } for (auto &[k, cnt] : mp1) { int ls = k.first; int s1 = k.second; int tp = (m - s1) % m; if (mp4.f ind(tp) == mp4. end ()) continue ; auto &v = mp4[tp]; auto it = lower_bound (v.begin (), v.end (), make_pair (ls + 2 , 0LL )); if (it != v.end ()) { ans += cnt * it->second; } } cout << ans + 1 ; return 0 ; }
复盘
打atcoder的原因: