比赛链接
D Strange Lunchbox
Description
题目链接
Solution
设 d p [ i ] [ j ] [ k ] dp[i][j][k] d p [ i ] [ j ] [ k ] 表示考虑前 i i i 个盒子,选了 j j j 个,takoyaki
数量为 k k k (大于 k k k 仍记为 k k k )时能获得 taiyaki
的最大值,状态转移如下:
选第 i i i 个盒子,则 d p [ i ] [ j ] [ m i n ( k , X ) ] ← d p [ i − 1 ] [ j − 1 ] [ k − A i ] + B i dp[i][j][min(k,X)] \leftarrow dp[i-1][j-1][k-A_i] + B_i d p [ i ] [ j ] [ m i n ( k , X ) ] ← d p [ i − 1 ] [ j − 1 ] [ k − A i ] + B i ,其中 A i ≤ k ≤ X + A i A_i \le k \le X+A_i A i ≤ k ≤ X + A i 。
不选第 i i i 个盒子,则 d p [ i ] [ j ] [ k ] ← d p [ i − 1 ] [ j ] [ k ] dp[i][j][k] \leftarrow dp[i-1][j][k] d p [ i ] [ j ] [ k ] ← d p [ i − 1 ] [ j ] [ k ] ,其中 0 ≤ k ≤ X 0 \le k \le X 0 ≤ k ≤ X 。
最后答案为 min 1 ≤ j ≤ N d p [ N ] [ j ] [ X ] \min \limits_{1 \le j \le N}dp[N][j][X] 1 ≤ j ≤ N min d p [ N ] [ j ] [ X ] 。
时间复杂度:O ( N 2 X ) O(N^2X) O ( N 2 X ) 。
Code
Strange Lunchbox 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> #define debug(x) cerr << #x << " = " << x << endl using namespace std ;typedef long long LL;const int MAXN = 3E2 + 5 ;const int MOD = 1E9 + 7 ;int n, x, y;int dp[2 ][MAXN][MAXN], a[MAXN], b[MAXN];signed main () { ios::sync_with_stdio(false ); cin >> n >> x >> y; for (int i = 1 ; i <= n; i++) cin >> a[i] >> b[i]; memset (dp, -1 , sizeof (dp)); dp[0 ][0 ][0 ] = 0 ; for (int i = 1 ; i <= n; i++) { memset (dp[i & 1 ], -1 , sizeof (dp[i & 1 ])); for (int j = 0 ; j <= i; j++) { for (int k = 0 ; k <= x + a[i]; k++) { if (j && k - a[i] >= 0 && dp[(i & 1 ) ^ 1 ][j - 1 ][k - a[i]] != -1 ) dp[i & 1 ][j][min(k, x)] = max(dp[i & 1 ][j][min(k, x)], dp[(i & 1 ) ^ 1 ][j - 1 ][k - a[i]] + b[i]); if (dp[(i & 1 ) ^ 1 ][j][min(k, x)] != -1 ) dp[i & 1 ][j][min(k, x)] = max( dp[i & 1 ][j][min(k, x)], dp[(i & 1 ) ^ 1 ][j][min(k, x)]); } } } for (int j = 0 ; j <= n; j++) if (dp[n & 1 ][j][x] >= y) { cout << j; return 0 ; } cout << -1 ; return 0 ; }
E Moat
Description
题目链接
Solution
由于矩阵大小为 4 ∗ 4 4*4 4 ∗ 4 ,我们可以枚举哪些格子没有被护城河包围,哪些格子被护城河包围。在一个合法方案中,所有城市应该被护城河包围,且被包围的格子和没有被包围的格子恰好形成两个联通块(规定边界的没有被包围的格子和外部一个超级源点相连),因此二进制枚举包围状态,然后用并查集求联通块个数即可。
Code
Moat 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 #include <bits/stdc++.h> #define debug(x) cerr << #x << " = " << x << endl using namespace std ;typedef long long LL;const int MAXN = 2E5 + 5 ;const int MOD = 1E9 + 7 ;int n, m, ans;int a[4 ][4 ], num[4 ][4 ], fa[17 ];int find (int x) { if (fa[x] != x) fa[x] = find(fa[x]); return fa[x]; } void unionn (int a, int b) { int r1 = find(a), r2 = find(b); if (r1 != r2) fa[r2] = r1; } signed main () { for (int i = 0 ; i < 4 ; i++) for (int j = 0 ; j < 4 ; j++) cin >> a[i][j], num[i][j] = i * 4 + j; for (int s = 0 ; s < (1 << 16 ); s++) { for (int i = 0 ; i <= 16 ; i++) fa[i] = i; for (int i = 0 ; i < 4 ; i++) for (int j = 0 ; j < 4 ; j++) { if (i) { if (!((s >> num[i][j]) & 1 ) && !((s >> num[i - 1 ][j]) & 1 )) unionn(num[i - 1 ][j], num[i][j]); if (((s >> num[i][j]) & 1 ) && ((s >> num[i - 1 ][j]) & 1 )) unionn(num[i][j], num[i - 1 ][j]); } if (j) { if (((s >> num[i][j]) & 1 ) && ((s >> num[i][j - 1 ]) & 1 )) unionn(num[i][j], num[i][j - 1 ]); if (!((s >> num[i][j]) & 1 ) && !((s >> num[i][j - 1 ]) & 1 )) unionn(num[i][j - 1 ], num[i][j]); } } for (int i = 0 ; i < 4 ; i++) for (int j = 0 ; j < 4 ; j++) if ((!i || !j || i == 3 || j == 3 ) && !((s >> num[i][j]) & 1 )) unionn(16 , num[i][j]); int cnt = 0 ; for (int i = 0 ; i <= 16 ; i++) if (fa[i] == i) cnt++; if (cnt != 2 ) continue ; bool ok = 1 ; for (int i = 0 ; i < 4 ; i++) for (int j = 0 ; j < 4 ; j++) if (a[i][j] && !((s >> num[i][j]) & 1 )) ok = 0 ; ans += ok; } cout << ans; return 0 ; }
F Cleaning Robot
Description
题目链接
Solution
设第 1 1 1 次执行指令访问到的点集为
V 1 = { ( X 1 , Y 1 ) , ( X 2 , Y 2 ) , … , ( X n , Y n ) } V_1=\{(X_1,Y_1),(X_2,Y_2),\dots,(X_n,Y_n)\} V 1 = { ( X 1 , Y 1 ) , ( X 2 , Y 2 ) , … , ( X n , Y n ) }
记终止位置为 ( a , b ) (a,b) ( a , b ) 。类似定义第 2 k 2k 2 k 次执行指令访问到的点集:
V 2 = { ( X 1 + a , Y 1 + b ) , ( X 2 + a , Y 2 + b ) , … , ( X n + a , Y n + b ) } V_2=\{(X_1+a,Y_1+b),(X_2+a,Y_2+b),\dots,(X_n+a,Y_n+b)\} V 2 = { ( X 1 + a , Y 1 + b ) , ( X 2 + a , Y 2 + b ) , … , ( X n + a , Y n + b ) }
⋮ \vdots ⋮
V k = { ( X 1 + ( k − 1 ) a , Y 1 + ( k − 1 ) b ) , ( X 2 + ( k − 1 ) a , Y 2 + ( k − 1 ) b ) , … , ( X n + ( k − 1 ) a , Y n + ( k − 1 ) b ) } V_k=\{(X_1+(k-1)a,Y_1+(k-1)b),(X_2+(k-1)a,Y_2+(k-1)b),\dots,(X_n+(k-1)a,Y_n+(k-1)b)\} V k = { ( X 1 + ( k − 1 ) a , Y 1 + ( k − 1 ) b ) , ( X 2 + ( k − 1 ) a , Y 2 + ( k − 1 ) b ) , … , ( X n + ( k − 1 ) a , Y n + ( k − 1 ) b ) }
对 ( X i , Y i ) ∈ V 1 (X_i,Y_i)∈V_1 ( X i , Y i ) ∈ V 1 ,记 d i d_i d i 为最小的满足 ( X i + d i a , Y i + d i b ) ∈ V 1 (X_i+d_ia,Y_i+d_ib)∈V_1 ( X i + d i a , Y i + d i b ) ∈ V 1 的正整数(没有则为 ∞ \infty ∞ )。由反证法可知 ( X i , Y i ) , … , ( X i + ( d i − 1 ) a , Y i + ( d i − 1 ) b ) (X_i,Y_i),\dots,(X_i+(d_i-1)a,Y_i+(d_i-1)b) ( X i , Y i ) , … , ( X i + ( d i − 1 ) a , Y i + ( d i − 1 ) b ) 不会与从 ( X j , Y j ) , j ≠ i (X_j,Y_j),j \neq i ( X j , Y j ) , j = i 开始执行过程中访问到的点重复,否则会存在一个更小的 d d d ,同时容易知道答案为 ∑ i = 1 n m i n ( d i , k ) \sum\limits_{i=1}^{n}min(d_i,k) i = 1 ∑ n m i n ( d i , k ) 。
接下来考虑如何求解 d d d 。
设 q i = ⌊ X i a ⌋ , S i = X i − a q i , T i = Y i − b q i q_i=\lfloor \frac{X_i}{a} \rfloor,S_i=X_i-aq_i,T_i=Y_i-bq_i q i = ⌊ a X i ⌋ , S i = X i − a q i , T i = Y i − b q i ,那么 ( X j , Y j ) = ( X i + d a , Y i + d b ) ⇔ ( S i , Y i ) = ( S j , T j ) ⇔ ( X j , Y j ) = ( X i + ( q j − q i ) a , Y i + ( q j − q i ) b ) (X_j,Y_j)=(X_i+da,Y_i+db)⇔(S_i,Y_i) = (S_j,T_j)⇔(X_j,Y_j)=(X_i+(q_j-q_i)a,Y_i+(q_j-q_i)b) ( X j , Y j ) = ( X i + d a , Y i + d b ) ⇔ ( S i , Y i ) = ( S j , T j ) ⇔ ( X j , Y j ) = ( X i + ( q j − q i ) a , Y i + ( q j − q i ) b ) 。我们先根据 ( S , T ) (S,T) ( S , T ) 对 q q q 分组,再进行组内排序,相邻两项的差就是 d d d 。
时间复杂度:O ( ∣ S ∣ l o g ∣ S ∣ ) O(|S|log|S|) O ( ∣ S ∣ l o g ∣ S ∣ ) 。
Code
Cleaning Robot 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 #include <bits/stdc++.h> #define debug(a) cerr << #a << " = " << a << endl using namespace std ;typedef long long LL;const int MAXN = 2E5 + 5 ;const int MOD = 1E9 + 7 ;int cnt = 0 ;LL k; string s;set <pair<int , int >> p;map <pair<int , int >, int > mp;vector <int > q[MAXN];signed main () { ios::sync_with_stdio(false ); cin >> s >> k; int a = 0 , b = 0 ; p.insert({a, b}); for (auto & c : s) { if (c == 'U' ) b--; if (c == 'D' ) b++; if (c == 'L' ) a--; if (c == 'R' ) a++; p.insert({a, b}); } if (!a && !b) return cout << p.size(), 0 ; for (auto & [x, y] : p) { int m1 = a ? (x % a + a) % a : (y % b + b) % b; int k = a ? (x - m1) / a : (y - m1) / b; int m2 = a ? y - k * b : x - k * a; int id = mp[{m1, m2}]; if (!id) { mp[{m1, m2}] = ++cnt; q[cnt].push_back(k); } else q[id].push_back(k); } LL ans = 0 ; for (int i = 1 ; i <= cnt; i++) { sort(q[i].begin(), q[i].end()); for (int j = 0 ; j < q[i].size() - 1 ; j++) ans += min(k, (LL)q[i][j + 1 ] - q[i][j]); ans += k; } cout << ans; return 0 ; }
G Propagation
Description
题目链接
Solution
将每次询问分为下面两步操作:
根据相邻点的修改状态更新当前点的值。
根据当前点的度修改周围节点的值/打上延迟修改标记。
对于操作 2 2 2 ,若当前点的度小于 B B B ,则直接将所有相邻点的值修改为当前点的值,并记录这些点的最后一次被修改的时刻(q i d qid q i d )为当前询问编号;若当前点的度大于等于 B B B ,则不立刻更新相邻点的值,而是对这个点记录当前询问编号为 s i g n sign s i g n ,同时用 t a g tag t a g 记录该点的值。
对于操作 1 1 1 ,由于对度大于等于 B B B 的点采用延迟更新,因此我们要遍历这些点,并根据这些点的状态更新当前点的值。具体的,如果某一度大于等于 B B B 的点的 s i g n sign s i g n 大于等于当前点 q i d qid q i d ,说明需要更新,将 t a g tag t a g 赋给当前点,同时将当前点的 q i d qid q i d 更新为 s i g n sign s i g n 。
由于度大于等于 B B B 的点不超过 2 M B \frac{2M}{B} B 2 M 个,因此总的复杂度为 O ( Q ( B + 2 M B ) O(Q(B+\frac{2M}{B}) O ( Q ( B + B 2 M ) 。由均值不等式可知,B B B 取 M \sqrt{M} M 比较合适。
类似题目:CF1580C Train Maintenance (参考代码 )、CF342E Xenia and Tree (参考代码 )
Code
Propagation 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 #include <bits/stdc++.h> #define debug(x) cerr << #x << " = " << x << endl using namespace std ;typedef long long LL;const int MAXN = 2E5 + 5 ;const int MOD = 1E9 + 7 ;int n, m, q, B;vector <int > G[MAXN];array <int , MAXN> v, sign, qid, deg, tag;signed main () { ios::sync_with_stdio(false ); cin >> n >> m >> q; B = max((int )sqrt (m), 1 ); for (int i = 1 , u, v; i <= m; i++) { cin >> u >> v; G[u].push_back(v); G[v].push_back(u); deg[v]++, deg[u]++; } auto cmp = [&](int & a, int & b) -> bool { return deg[a] > deg[b]; }; for (int i = 1 ; i <= n; i++) v[i] = i, sort(G[i].begin(), G[i].end(), cmp); for (int i = 1 , x; i <= q; i++) { cin >> x; for (auto & to : G[x]) { if (deg[to] < B) break ; if (sign[to] > qid[x]) { qid[x] = sign[to]; v[x] = tag[to]; } } if (deg[x] < B) for (auto & to : G[x]) v[to] = v[x], qid[to] = i; else sign[x] = i, tag[x] = v[x]; } for (int i = 1 ; i <= n; i++) { for (auto & to : G[i]) { if (deg[to] < B) break ; if (sign[to] > qid[i]) { qid[i] = sign[to]; v[i] = tag[to]; } } cout << v[i] << " " ; } return 0 ; }