zoukankan      html  css  js  c++  java
  • CodeForces

    题目链接: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
    ",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
    ",ans);
        return 0;
    }
    路漫漫兮
  • 相关阅读:
    Asp.Net Core 2.0 项目实战(7)MD5加密、AES&DES对称加解密
    Asp.Net Core 2.0 项目实战(8)Core下缓存操作、序列化操作、JSON操作等Helper集合类
    Java后端开发-SSM框架的图片上传
    个人作业——软件工程实践总结&个人技术博客
    个人作业——软件评测
    结对第二次作业——某次疫情统计可视化的实现
    结对第一次—疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    my codestyle
    alibaba-java-style-guide
  • 原文地址:https://www.cnblogs.com/lonely-wind-/p/13269374.html
Copyright © 2011-2022 走看看