CF253D题解

本题需要文件读写。如果没过可能是这个原因。

最朴素的方法是枚举这个矩阵,需要确定矩阵的四条边,来判断是否满足条件,运用二位前缀和计算 a 的数量,用前缀和优化后时间复杂度为 \(O(n^4)\),不能通过。

显然一个矩阵的子矩阵的 a 的数量小于等于该矩阵的 a 的数量。
由此可以得出,假设一个符合要求的矩阵内部有一个四个角相等的矩阵,那么这个矩阵一定符合要求。
可以通过这个性质来统计矩阵的数量吗?

这四个角需要相等的条件也可以看作是两个同一列的相同字符端点对相等且对应端点在同一行。
枚举统计的矩阵的所在行,我们就可以在这个端点对上做文章。

由于上述性质,我们可以先找出相同字符端点对,利用一个双指针,左端点表示矩阵的左侧的端点对,右端点表示矩阵可能的右侧的端点对,来维护一个 a 符合要求的可能的右侧端点对的一个区间。
我们在统计答案的时候不断累加左开右闭的两个指针的区间、与左指针代表的端点对匹配的右侧端点对个数,同时不断移动左右指针即可。

这个过程均摊下来是 \(O(n)\) 的。程序整体的时间复杂度为 \(O(n^3)\),可以通过。

代码如下。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
constexpr int MAXN=400+10,MAXM=400+10;
int n,m,k,sum[MAXN][MAXM],pa[26],pc[MAXM];
char jz[MAXN][MAXM];
ll ans;
int gc(){
    int x=getchar();
    while(x==' '||x=='\r'||x=='\n')x=getchar();
    return x;
}
int main(){
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;++i)
        for(int j=1;j<=m;++j){
            jz[i][j]=gc();
            sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(jz[i][j]=='a');
        }
    for(int i=1;i<n;++i){
        for(int j=i+1;j<=n;++j){
            int p=0;
            for(int k=1;k<=m;++k){
                if(jz[i][k]==jz[j][k]){
                    pc[++p]=k;
                }
            }
            for(int i1=0;i1<26;++i1)pa[i1]=0;
            int lp=1,rp=1;
            while(lp<p){
                while(rp<p&&
                sum[j][pc[rp+1]]-sum[i-1][pc[rp+1]]-sum[j][pc[lp]-1]+sum[i-1][pc[lp]-1]<=k)
                    {++rp;++pa[jz[j][pc[rp]]-'a'];}
                ans+=pa[jz[j][pc[lp]]-'a'];
                ++lp;
                --pa[jz[j][pc[lp]]-'a'];
                while(rp<lp){++rp;++pa[jz[j][pc[rp]]-'a'];}
            }
        }
    }
    printf("%lld\n",ans);
    return 0;
}
posted @ 2024-02-18 19:32  LiJoQiao  阅读(3)  评论(0编辑  收藏  举报