ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

Description

给定一个n行m列的矩阵,请对于每个长宽均为k的连续子正方形,统计里面出现过的数值的种类数。

Input

第一行包含三个正整数n,m,k(n,m<=3000,k<=min(n,m))。
接下来n行,每行m个正整数a[i][j](1<=a[i][j]<=100000),表示矩阵中每个位置的数值。

Output

输出一行两个整数M和S。
设f(i,j)表示以(i,j)为左上角的正方形内出现过的数值的种类数,则M表示f的最大值,S表示f的总和。

对每种颜色分别算贡献,一个点对一个边长k的正方形内每个位置贡献1,但同色贡献只算一次,这是一个正方形求并问题。考虑扫描线,由于边长固定,每个正方形进入和离开扫描线时,至多改变扫描线一个区间的状态,求这个区间的端点,则需要在扫描线上查前趋后继,可以用线段树维护。

#include<bits/stdc++.h>
typedef unsigned int u32;
const u32 A=-1;
const int N=1e5+7,M=3007;
char ib[M*M*8],*ip=ib;
inline int _(){
    int x=0;
    while(*ip<48)++ip;
    while(*ip>47)x=x*10+*ip++-48;
    return x;
}
u32 bs[M][2][M/32+2],t0[N][4],t1[N][M/32+2];
int n,m,k,mx,a[M][M],s[M][M],pv[N];
long long sum;
inline void _xor(u32*a,int x){a[x>>5]^=1<<x;}
inline int _get(u32*a,int x){return a[x>>5]>>x&1;}
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a<b?a:b;}
#define ctz(x) __builtin_ctz(x)
#define clz(x) (31^__builtin_clz(x))
inline void cal(int x,int y,int w,int sgn){
    int L=-10000,R=10000,p1=y>>5,p2=y>>10,p3;
    u32 v;
    v=t1[w][p1]&A<<y;
    if(v)R=p1<<5|ctz(v);
    else{
        v=t0[w][p2]&A<<p1<<1;
        if(v){
            p3=p2<<5|ctz(v);
            R=p3<<5|ctz(t1[w][p3]);
        }else for(int i=p2+1;i<3;++i)if(t0[w][i]){
            p3=i<<5|ctz(t0[w][i]);
            R=p3<<5|ctz(t1[w][p3]);
            break;
        }
    }
    v=t1[w][p1]&A>>(31^y);
    if(v)L=p1<<5|clz(v);
    else{
        v=t0[w][p2]&A>>(31^p1)>>1;
        if(v){
            p3=p2<<5|clz(v);
            L=p3<<5|clz(t1[w][p3]);
        }else for(int i=p2-1;i>=0;--i)if(t0[w][i]){
            p3=i<<5|clz(t0[w][i]);
            L=p3<<5|clz(t1[w][p3]);
            break;
        }
    }
    
    L=max(y,L+k);
    R=min(min(m+1,y+k),R);
    if(L<R)s[x][L]+=sgn,s[x][R]-=sgn;
}
inline void del(int x,int y,int w){
    _xor(t1[w],y);
    if(!t1[w][y>>5])_xor(t0[w],y>>5);
    cal(x,y,w,-1);
}
inline void ins(int x,int y,int w){
    cal(x,y,w,1);
    if(!t1[w][y>>5])_xor(t0[w],y>>5);
    _xor(t1[w],y);
}
int main(){
    fread(ib,1,sizeof(ib),stdin);
    n=_();m=_();k=_();
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            a[i][j]=_();
        }
    }
    for(int j=1;j<=m;++j){
        for(int i=1;i<=n;++i){
            int x=a[i][j],&y=pv[x];
            if(y&&y>i-k)_xor(bs[y][0],j),_xor(bs[i][1],j);
            y=i;
        }
        for(int i=1;i<=n;++i)pv[a[i][j]]=0;
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            if(i>k&&!_get(bs[i-k][0],j))del(i,j,a[i-k][j]);
            if(!_get(bs[i][1],j))ins(i,j,a[i][j]);
        }
    }
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j)s[i][j]+=s[i][j-1];
        for(int j=1;j<=m;++j)s[i][j]+=s[i-1][j];
        if(i>=k)for(int j=k;j<=m;++j){
            sum+=s[i][j];
            if(s[i][j]>mx)mx=s[i][j];
        }
    }
    printf("%d %lld\n",mx,sum);
    return 0;
}

 

posted on 2017-11-28 01:46  nul  阅读(548)  评论(0编辑  收藏  举报