[Codeforces Round #394 (Div. 2)] - F Dasha and Photos

洛谷传送门
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 k1个矩阵的距离之和最小, 并输出这个最小值。

输入输出格式

输入格式

第一行三个正整数 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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值