joi2022_yo2_c 国土分割 (Land Division) 题解
1.CSES 1667 Message Route 题解2.P3956 棋盘 题解3.abc233_f Swap and Sort 题解4.abc233_e Σ[k=0..10^100]floor(X/10^k) 题解5.abc233_d Interval 题解6.abc233_c Product 题解7.abc249_f Ignore Operations 题解8.abc249_d Index Trio 题解9.abc248_e K-colinear Line 题解10.abc247_f Cards 题解11.CF1066C Books Queries 题解12.P1038 神经网络 题解13.SeekLuna P1362 拓扑排序 3 题解14.abc232_e Rook Path 题解15.abc235_e MST + 1 题解16.abc234_e Arithmetic Number 题解17.P8786 李白打酒加强版 题解18.abc235_d Multiply and Rotate 题解19.CF1095D Circular Dance 题解20.P6201 & P1985 Fliptile S 题解21.CF1183C Computer Game 题解22.CF1095E Almost Regular Bracket Sequence 题解23.abc256_e Takahashi's Anguish 题解24.abc260_g Scalene Triangle Area 题解25.P8714 填空问题 题解26.abc252_d Distinct Trio 题解27.abc252_f Bread 题解28.abc253_e Distance Sequence 题解29.abc250_e Prefix Equality 题解30.abc250_d 250-like Number 题解31.arc164_a Ternary Decomposition 题解32.abc275_f Erase Subarrays 题解33.abc275_e Sugoroku 4 题解34.abc274_d Robot Arms 2 题解35.abc260_f Find 4-cycle 题解36.abc260_e At Least One 题解37.abc273_e Notebook 题解38.abc271_f XOR on Grid Path 题解39.abc271_e Subsequence Path 题解40.abc271_c Manga 题解41.abc269_f Numbered Checker 题解42.abc270_f Transportation 题解43.CF1077E Thematic Contests 题解44.CF1935D Exam in MAC 题解45.CF1144G Two Merged Sequences 题解
46.joi2022_yo2_c 国土分割 (Land Division) 题解
47.P3588 PUS 题解48.CF1946F Nobody is needed 题解国土分割 (Land Division)
推销我的洛谷博客。
题意
给定一个
数据范围
。 。
思路
闲话
老师给我们复现了一下,场切了,心路历程如下。
第一眼:好像有些难度啊。
第二眼:
第三眼:欸如果
第四眼:哦
正题
看起来挺吓唬人,但数据范围太小,所以考虑枚举。
枚举最左上角的小矩阵的大小,假设这个矩阵的右下角为
那么对于列的分割方法,你可以通过前
-
对于一组
有几种分割方式呢?正如闲话中所说的, 都为正数,那么可以发现对于每一组 都至多有一种分割方案。 -
对于求一个矩阵的
之和,不难想到二维前缀和优化。
详细见代码。
复杂度
- 时间:
。 - 空间:
。
Code
点击查看代码
#include <bits/stdc++.h> using namespace std; int n, m, a[55][55], sum[55][55], cnt, stk[55], top, ans; int C (int x, int y, int a, int b) { // 二维前缀和求解矩阵和 return sum[a][b] - sum[x - 1][b] - sum[a][y - 1] + sum[x - 1][y - 1]; } void Solve (int i, int j) { // 对于一组 (i, j),判断是否具有合法的分割方案 cnt = C(1, 1, i, j), top = 1, stk[1] = j; // cnt 为每个矩阵的和,stk 用于记录在哪些列需要分割 for (int k = j + 1; k <= m; k++) { // 利用前 i 行推出在哪些列需要分割 if (C(1, stk[top] + 1, i, k) == cnt) { // 找出来了一个矩阵 stk[++top] = k; } else if (C(1, stk[top] + 1, i, k) > cnt) { // 不合法 return ; } } if (stk[top] != m) { // 最右上角的矩阵和没有达到 cnt return ; } int lst = i; for (int k = i + 1; k <= n; k++) { // 已知在哪些列需要分割,推在哪些行需要分割 bool f = 0; for (int l = 1; l <= top; l++) { if (C(lst + 1, stk[l - 1] + 1, k, stk[l]) < cnt) { // 这一行还不够 f = 1; } else if (C(lst + 1, stk[l - 1] + 1, k, stk[l]) > cnt) { // 这一行有矩阵和已经超过了 cnt,不可能合法 return ; } } if (!f) { // 找到了满足要求的一行 lst = k; } } if (lst != n) { // 最下方的矩阵还不合法 return ; } // cout << i << ' ' << j << '\n'; ans++; } int main () { ios::sync_with_stdio(0), cin.tie(0); //freopen("div.in", "r", stdin); //freopen("div.out", "w", stdout); cin >> n >> m; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> a[i][j], sum[i][j] = sum[i][j - 1] + a[i][j]; } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { sum[i][j] += sum[i - 1][j]; // 逐维前缀和 } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { Solve(i, j); } } cout << ans - 1; // 由于题目要求至少分割一次,则需要减去 (n, m) 这一组 return 0; }
本文作者:wnsyou の blog
本文链接:https://www.cnblogs.com/wnsyou-blog/p/18292535/joi2022_yo2_c
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步