洛谷传送门
Codeforces传送门
题目大意
给你一个
n
×
m
n\times m
n×m的方格, 每个格子里有一个小写英文字母。
现在你有
k
k
k个
n
×
m
n\times m
n×m的方格, 这些方格都是在给出方格的基础上将一个矩形区域的方格中的字母全部变成一种得到的。
定义两个方格的距离为所有格子中字母在字母表中位置的差。 你要找到
k
k
k个方格中的一个方格, 满足它到其他
k
−
1
k-1
k−1个矩阵的距离之和最小, 并输出这个最小值。
输入输出格式
输入格式
第一行三个正整数
n
,
m
,
k
n, m, k
n,m,k。
以下
n
n
n行, 每行
m
m
m个小写字母,表示原始方格。
以下
k
k
k行, 每行
4
4
4个正整数
a
i
,
b
i
,
c
i
,
d
i
a_i,b_i,c_i,d_i
ai,bi,ci,di和一个字符
c
h
ch
ch, 表示这个方格是将原始方格左上角为
a
i
a_i
ai行
b
i
b_i
bi列的格子、 右下角为
c
i
c_i
ci行
d
i
d_i
di列的格子中的字母全部替换成
c
h
ch
ch得到的。
输出格式
输出一行一个整数, 表示最小的距离之和。
输入输出样例
输入样例#1:
3 3 2
aaa
aaa
aaa
1 1 2 2 b
2 2 3 3 c
输出样例#1:
10
输入样例#2:
5 5 3
abcde
eabcd
deabc
cdeab
bcdea
1 1 3 4 f
1 2 3 3 e
1 3 3 4 i
输出样例#2:
59
解题分析
本来以为是一道牛逼的数据结构题, 然后发现是个暴力…
直接维护所有矩形和原矩形的距离和, 和只涂某种颜色和所有矩形的距离和, 用前缀和优化即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <climits>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MX 1050
#define SIZ 300500
int n, m, K;
template <class T> IN T max(T a, T b) {return a > b ? a : b;}
template <class T> IN T min(T a, T b) {return a < b ? a : b;}
char mp[MX][MX], let[SIZ][2];
int a[SIZ], b[SIZ], c[SIZ], d[SIZ], cnt[26];
ll s[26][MX][MX], ori[MX][MX], rep[26][MX][MX];
ll calc(ll dat[MX][MX], R int i)
{return dat[a[i] - 1][b[i] - 1] - dat[c[i]][b[i] - 1] - dat[a[i] - 1][d[i]] + dat[c[i]][d[i]];}
int main(void)
{
int foo;
scanf("%d%d%d", &n, &m, &K);
for (R int i = 1; i <= n; ++i)
scanf("%s", mp[i] + 1);
for (R int i = 1; i <= K; ++i)
{
scanf("%d%d%d%d", &a[i], &b[i], &c[i], &d[i]);
scanf("%s", let[i]);
foo = let[i][0] - 'a';
s[foo][a[i]][b[i]]++;
s[foo][a[i]][d[i] + 1]--;
s[foo][c[i] + 1][b[i]]--;
s[foo][c[i] + 1][d[i] + 1]++;
}
for (R int i = 1; i <= n; ++i)
for (R int j = 1; j <= m; ++j)
{
int ct = 0, tot = 0;
for (R int k = 0; k < 26; ++k)
{
cnt[k] = s[k][i][j] += s[k][i - 1][j] + s[k][i][j - 1] - s[k][i - 1][j - 1];
ct += cnt[k], tot += cnt[k] * k;
}
foo = mp[i][j] - 'a';
cnt[foo] += K - ct;
tot += (K - ct) * foo;
for (R int k = 0; k < 26; ++k)
{
if (k == foo) ori[i][j] = ori[i - 1][j] + ori[i][j - 1] - ori[i - 1][j - 1] + tot;
rep[k][i][j] = rep[k][i - 1][j] + rep[k][i][j - 1] - rep[k][i - 1][j - 1] + tot;
if (k) cnt[k] += cnt[k - 1];
tot += cnt[k] - (K - cnt[k]);
}
}
long long ans = LONG_LONG_MAX;
for (R int i = 1; i <= K; ++i)
ans = min(ans, ori[n][m] - calc(ori, i) + calc(rep[let[i][0] - 'a'], i));
printf("%lld\n", ans);
}