暑假集训第一次杭电多校。
题目链接
I 「Assertion」
签到题,知道抽屉原理就行了。
时间复杂度:\(O(1)\)
空间复杂度:\(O(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 #include <iostream> void solve () { int n, m, d; std::cin >> n >> m >> d; if (d <= (m + n - 1 ) / n) { std::cout << "Yes\n" ; } else { std::cout << "No\n" ; } }int main () { std::ios::sync_with_stdio (false ); std::cin.tie (nullptr ); std::cout.tie (nullptr ); int numTest; std::cin >> numTest; while (numTest--) solve (); return 0 ; }
E 「Cyclically Isomorphic」
判断两个字符串 str1
和 str2
是否符合
"Cyclically Isomarphic" 的性质,只需要判断 str2
是否是
str1 + str1
的子串即可。
时间复杂度:\(O(Qm)\) (重复的查询不计入)
空间复杂度:\(O(nm)\)
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 #include <iostream> #include <vector> #include <map> void solve () { int n, m, q; std::cin >> n >> m; std::vector<std::string> arr (n) ; std::vector<std::string> pat (n) ; for (int i = 0 ; i < n; i++) { std::string str; std::cin >> str; arr[i] = str; pat[i] = str + str; } std::map<std::pair<int , int >, bool > res; std::cin >> q; for (int i = 0 , x, y; i < q; i++) { std::cin >> x >> y; x--; y--; if (x > y) { int tmp = x; x = y; y = tmp; } if (res.find ({x, y}) == res.end ()) { res[{x, y}] = pat[x].find (arr[y]) != std::string::npos; } std::cout << (res[{x, y}] ? "Yes\n" : "No\n" ); } }int main () { std::ios::sync_with_stdio (false ); std::cin.tie (nullptr ); std::cout.tie (nullptr ); int numTest; std::cin >> numTest; while (numTest--) solve (); return 0 ; }
B 「City Upgrading」
树上 DP,选定一个根节点,从叶节点向上
DP,状态转移方程还是比较好想的,如果父节点没有被选取,则至少要有一个子节点被选取。
若父节点被选取,则子节点的子树必须都被覆盖。
时间复杂度:\(O(n)\)
空间复杂度:\(O(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 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 #include <iostream> #include <algorithm> #include <vector> using i64 = long long ;const i64 inf = 0x7f7f7f7f7f7f ll;class Solution {private : std::vector<int > cost; std::vector<std::vector<int >> g; std::vector<std::vector<i64>> dp; void dfs (int x, int fa) { dp[x][1 ] = cost[x]; for (int v : g[x]) { if (v != fa) { dfs (v, x); dp[x][0 ] += std::min (dp[v][0 ], dp[v][1 ]); i64 res_1 = std::min (dp[v][0 ], dp[v][1 ]); i64 res_2 = 0 ; for (int sv : g[v]) { if (sv != x) { res_2 += std::min (dp[sv][0 ], dp[sv][1 ]); } } dp[x][1 ] += std::min (res_1, res_2); } } i64 res = dp[x][0 ]; dp[x][0 ] = inf; for (int v : g[x]) { if (v != fa) { dp[x][0 ] = std::min (dp[x][0 ], res - std::min (dp[v][0 ], dp[v][1 ]) + dp[v][1 ]); } } }public : void solve () { int n; std::cin >> n; cost.resize (n); for (int i = 0 ; i < n; i++) std::cin >> cost[i]; g.resize (n); for (int i = 0 , x, y; i < n - 1 ; i++) { std::cin >> x >> y; x--; y--; g[x].push_back (y); g[y].push_back (x); } dp.resize (n, std::vector <i64>(2 , 0 )); dfs (0 , -1 ); std::cout << std::min (dp[0 ][0 ], dp[0 ][1 ]) << '\n' ; } };int main () { std::ios::sync_with_stdio (false ); std::cin.tie (nullptr ); std::cout.tie (nullptr ); int numTest; std::cin >> numTest; while (numTest--) Solution ().solve (); return 0 ; }
L 「Play on Tree」
给定一颗树,两人轮流删掉一个子树,删掉最后一个节点的人输掉比赛。则叶节点的
SG 值为 0,非叶节点的 SG 值为其所有子节点的 (SG 值 + 1) 的异或和。
对于不同的根节点,可以考虑换根 DP,从而得到每一个节点作为根节点的 SG
值。
时间复杂度:\(O(n)\)
空间复杂度:\(O(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 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 #include <iostream> #include <cstring> using i64 = long long ;const int MAX_N = 2e5 + 5 ;int first[MAX_N];struct { int to; int next; } edges[2 * MAX_N];int cnt = 0 ;void addEdge (int x, int y) { edges[cnt] = {y, first[x]}; first[x] = cnt++; }int sg1[MAX_N];int sg2[MAX_N];void dfs1 (int v, int fa) { sg1[v] = 0 ; for (int e = first[v]; e != -1 ; e = edges[e].next) { int x = edges[e].to; if (x == fa) continue ; dfs1 (x, v); sg1[v] ^= (sg1[x] + 1 ); } }void dfs2 (int v, int fa) { for (int e = first[v]; e != -1 ; e = edges[e].next) { int x = edges[e].to; if (x == fa) continue ; sg2[x] = ((sg2[v] ^ (sg1[x] + 1 )) + 1 ) ^ sg1[x]; dfs2 (x, v); } }const int mod = 1e9 + 7 ;int quickPow (int x, int n) { int res = 1 ; while (n) { if (n & 1 ) res = (i64)res * x % mod; x = (i64)x * x % mod; n >>= 1 ; } return res; }void solve () { cnt = 0 ; memset (first, 0xff , sizeof (first)); int n; std::cin >> n; for (int i = 0 , x, y; i < n - 1 ; i++) { std::cin >> x >> y; x--, y--; addEdge (x, y); addEdge (y, x); } dfs1 (0 , -1 ); sg2[0 ] = sg1[0 ]; dfs2 (0 , -1 ); int res = 0 ; for (int i = 0 ; i < n; i++) res += sg2[i] != 0 ; std::cout << (i64)res * quickPow (n, mod - 2 ) % mod << '\n' ; }int main () { std::ios::sync_with_stdio (false ); std::cin.tie (nullptr ); std::cout.tie (nullptr ); int numTest; std::cin >> numTest; while (numTest--) solve (); return 0 ; }