CodeForces - 253D Table with Letters - 2 (有技巧的暴力枚举)

题目链接:https://codeforces.com/problemset/problem/253/D

题目大意:对于一个字符矩阵,找其中的子块,要求有两个其一子块中包含字符a的个数不超过k,其二子块的四个角的字符相同。且子块的行数大于等于2,列数大于等于2

Examples

Input
3 4 4
aabb
baab
baab
Output
2
Input
4 5 1
ababa
ccaca
ccacb
cbabc
Output
1

emmm,首先,最为暴力的方法就是直接枚举上边界、下边界、左边界和右边界,那么复杂度为$O(n^4)$会T掉,暴力写法如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;

const int mac=450;

char s[mac][mac];
int as[mac][mac];

int main(int argc, char const *argv[])
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n,m,lim;
    cin>>n>>m>>lim;

    for (int i=1; i<=n; i++)
        cin>>s[i]+1;
    for (int i=1; i<=n; i++)
        for (int j=1; j<=m; j++)
            as[i][j]=as[i-1][j]+as[i][j-1]-as[i-1][j-1]+(s[i][j]=='a'?1:0);

    int ans=0;
    for (int i=1; i<n; i++){//枚举上行
        for (int j=i+1; j<=n; j++){//枚举下行
            for (int l=1; l<m; l++){//枚举左边界
                for (int r=l+1; r<=m; r++){//枚举右边界
                    if (as[j][r]-as[i-1][r]-as[j][l-1]+as[i-1][l-1]>lim) continue;
                    if (s[i][l]==s[i][r] && s[i][r]==s[j][r] && s[j][r]==s[j][l])
                        ans++; 
                }
            }
        }
    }
    printf("%d\n",ans);
    return 0;
}
View Code

接下来我们就是想办法优化它了。枚举左边界的时候判断左上角和左下角的字符,优化一下,接下来就是对该列该宽度下的上下字符一样的情况,我们用数组来保存每个字符在的合法数量,直接将该字符对应的ASCLL位置进行+1操作:

for (int l=1; l<m; l++) { //枚举左边界
    if (s[i][l]!=s[j][l]) continue;
    cnt[s[i][l]]--;
    while (r<=m && as[j][r]-as[i-1][r]-as[j][l-1]+as[i-1][l-1]<=lim) {
        if (s[i][r]==s[j][r]) cnt[s[j][r]]++;
        r++;
    }
    if (cnt[s[i][l]]>0) ans+=cnt[s[i][l]];
}

这样就大大优化了时间,其中cnt数组刚开始-1是由于r也是从1开始的,他需要去一下重。

那么优化后的代码也就出来了:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;

typedef long long ll;
const int mac=450;

char s[mac][mac];
int as[mac][mac],cnt[200];

int main(int argc, char const *argv[])
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int n,m,lim;
    cin>>n>>m>>lim;

    for (int i=1; i<=n; i++)
        cin>>s[i]+1;
    for (int i=1; i<=n; i++)
        for (int j=1; j<=m; j++)
            as[i][j]=as[i-1][j]+as[i][j-1]-as[i-1][j-1]+(s[i][j]=='a'?1:0);

    ll ans=0;
    for (int i=1; i<n; i++){//枚举上行
        for (int j=i+1; j<=n; j++){//枚举下行
            memset(cnt,0,sizeof cnt);
            int r=1;
            for (int l=1; l<m; l++){//枚举左边界
                if (s[i][l]!=s[j][l]) continue;
                cnt[s[i][l]]--;
                while (r<=m && as[j][r]-as[i-1][r]-as[j][l-1]+as[i-1][l-1]<=lim){
                    if (s[i][r]==s[j][r]) cnt[s[j][r]]++;
                    r++;
                }
                if (cnt[s[i][l]]>0) ans+=cnt[s[i][l]];
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2020-07-08 21:42  lonely_wind  阅读(200)  评论(0编辑  收藏  举报