错综的统一
错综的统一
题目描述
小红拿到了一个仅由 'r'、'e'、'd' 三种字母组成的矩阵,共 行 列。
小红定义一个矩形区域是美丽的,当且仅当:在该矩形区域中,任意横向或者纵向取一个长度大于1的连续子串时,该字符串都不是回文的。
现在小红有若干次询问,每次给定一个矩形区域,问最少修改多少字符(字符只能修改为 'r'、'e'、'd'),可以使得该区域为“美丽的”?
输入描述:
第一行输入三个正整数 ,代表矩阵的行和列,以及询问次数。
接下来的 行,每行输入一个长度为 的、只含有 'r'、'e'、'd' 三种字母字符串,用来表示字符矩阵。
接下来的 行,每行输入四个正整数 ,代表每次询问的矩形区域的左上角坐标 和右下角坐标 。
数据范围:
输出描述:
输出 行,每行输出每次询问的答案。
示例1
输入
3 3 2
rrr
rdd
edr
1 1 1 3
1 1 2 1
输出
2
1
说明
对于第一次询问,子矩阵是 "rrr",需要至少修改 2 个字符才能保证不包含长度超过 1 的回文子串。
对于第二次询问,只需要把第一个字符改成 'd' 或者 'e' 即可,只需要 1 次操作。(改第二行第一列字符也可以)。
解题思路
要保证横向或纵向任意长度大于 的连续子串不是回文串,只需保证横向与纵向任意长度为 和 的连续子串不是回文串即可。
先考虑横向的情况,由于只有 r
、e
、d
这 种字符,因此若要保证横向上不存在长度为 和 的回文串,那么合法的字符串只有以下 种:redredred...
、edredredr...
、dredredre...
、derderder...
、erderderd...
、rderderde...
,即 red
、edr
、dre
、der
、erd
、rde
的循环。
再考虑纵向的情况,假定矩阵的第一行是 redredred...
这种形式,将上一行循环左移或循环右移一个单位作为下一行,就会得到 redredred...
、
edredredr...
dredredre...
...redredred...
,这种构造方式使得纵向上与横向相同,都不会存在回文串。注意在选定移动的方向后就不能再改变了。同理剩余的 种情况。
dredredre...
edredredr...
...
由于横向上的字符串有 种选择,有 种方向构造下一行,因此满足横向与纵向任意长度为 和 的连续子串不是回文串的矩阵就只有 种。对于给定的询问 ,我们只需枚举这 种矩阵并统计该区域内不同的单元格的数量,最后取最小值即可,可以预处理 个二维前缀和来加速这个过程。
我写的程序并没有直接把这 种矩阵创建出来,而是先分别枚举 种字符串 str
,再枚举 个方向。对于左移方向,str[(i + j) % 3]
就对应矩阵 g[i][j]
上的字符。对于右移方向,str[((j - i) % 3 + 3) % 3]
就对应矩阵 g[i][j]
上的字符。这样就可以知道 种矩阵每个格子是哪个字符了。
最后还要特判 为 的情况。除了要枚举上面分析到的 种矩阵外,还要考虑以下 种矩阵:re
、
erer
、
rerd
、
drdr
、
rded
、
dede
,这是 种矩阵里面不存在的状态。
ed
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 510;
char g[N][N];
int s[12][N][N];
int get(int k, int x1, int y1, int x2, int y2) {
return s[k][x2][y2] - s[k][x1 - 1][y2] - s[k][x2][y1 - 1] + s[k][x1 - 1][y1 - 1];
}
int main() {
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= n; i++) {
scanf("%s", g[i] + 1);
}
int cnt = 0;
for (string str : {"red", "edr", "dre", "der", "erd", "rde"}) {
for (int k = 0; k <= 1; k++, cnt++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
int w = 0;
if (!k && str[(i + j) % 3] != g[i][j]) w = 1;
if (k && str[((j - i) % 3 + 3) % 3] != g[i][j]) w = 1;
s[cnt][i][j] = w;
}
}
}
}
for (int k = 0; k < cnt; k++) {
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
s[k][i][j] += s[k][i - 1][j] + s[k][i][j - 1] - s[k][i - 1][j - 1];
}
}
}
while (k--) {
int x1, y1, x2, y2;
scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
int ret = 1e9;
for (int i = 0; i < cnt; i++) {
ret = min(ret, get(i, x1, y1, x2, y2));
}
if (x2 - x1 == 1 && y2 - y1 == 1) {
for (string str : {"re", "er", "rd", "dr", "ed", "de"}) {
int sum = 0;
if (str[0] != g[x1][y1]) sum++;
if (str[1] != g[x1][y2]) sum++;
if (str[1] != g[x2][y1]) sum++;
if (str[0] != g[x2][y2]) sum++;
ret = min(ret, sum);
}
}
printf("%d\n", ret);
}
return 0;
}
参考资料
【题目讲解】2024牛客寒假算法基础集训营6 讲题:https://www.bilibili.com/video/BV1WZ42127qx/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/18045498
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效