CodeForces 253D Table with Letters - 2(枚举技巧)

题目链接:点击打开链接

题意,给出一个字符表,问有多少子表满足:四个角字符相同,子表内a字符的数量不超过k。

思路:不加入任何技巧的话,上行、下行、左列、右列四重枚举,O(n^4),复杂度太高,可以加入一点枚举技巧,减少一层枚举。

首先要利用前缀和预处理,a[i][j]表示第i行,1 ~ j列字符a的数量。

技巧的话,有点形似尺取法,但有区别,尺取法是每次移动一个坐标的le,然后尽可能右移rig,直到le == rig结束;此处是每次移动一个坐标的bottom(下行),当top(上行)位置不合适再下移,当bottom到达上限就结束,不用枚举到top == bottom的原因又用到了另一个技巧:开了一个count数组,记录当前子表每行中最左列等于最右列的数量,当bottom扫过去,之前每行的结果已经记录了,直接利用即可。

// CodeForces 253D Table with Letters - 2 运行/限制:624ms/2000ms
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
char map[405][405];//原表
int a[405][405];//前缀和,a[i][j]表示第i行,1 ~ j列字符a的数量
int count[30];//计算当前子表每行中最左列等于最右列的数量
int main(){
	int n, m, k;
	long long ans;
	freopen("input.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
	while (scanf("%d%d%d", &n, &m, &k) != EOF) {
		ans = 0;
		memset(a, 0, sizeof(a));
		for (int i = 1; i <= n; i++) {
			scanf("%s", map[i] + 1);
			for (int j = 1; j <= m; j++) {
				a[i][j] = a[i][j - 1] + (map[i][j] == 'a');//计算前缀和
			}
		}
		for (int le = 1; le < m; le++) {//左列
			for (int rig = le + 1; rig <= m; rig++) {//右列
				int top = 1, bottom, sum = 0;//top:上行 bottom:下行 sum:字符a数量
				memset(::count, 0, sizeof(::count));
				for (bottom = top; bottom <= n; bottom++) {
					sum += a[bottom][rig] - a[bottom][le - 1];//更新sum
					if (map[bottom][le] == map[bottom][rig]) {//更新count数组
						::count[map[bottom][le] - 'a']++;
					}
					while (sum > k && top <= bottom) {//sum超出范围,下移top
						//下移前先处理sum和count数组
						sum -= a[top][rig] - a[top][le - 1];
						if (map[top][le] == map[top][rig]) {
							::count[map[top][le] - 'a']--;
						}
						top++;
					}
					if (top < bottom && map[bottom][le] == map[bottom][rig]) {
						ans += ::count[map[bottom][le] - 'a'] - 1;
					}
				}
			}
		}
		printf("%I64d\n", ans);
	}
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值