CodeForces 253D Table with Letters

来源:互联网 发布:maven java目录下的xml 编辑:程序博客网 时间:2024/06/07 01:54

题目链接:点击打开链接

题意,给出一个字符表,问有多少子表满足:四个角字符相同,子表内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];//更新sumif (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;}



原创粉丝点击