标签:扫描线
题目
Description
给定一个n行m列的矩阵,请对于每个长宽均为k的连续子正方形,统计里面出现过的数值的种类数。
Input
第一行包含三个正整数\(n,m,k(n,m\leq 3000,k\leq min(n,m))\)。
接下来n行,每行m个正整数\(a[i][j](1\leq a[i][j]\leq 100000)\),表示矩阵中每个位置的数值。
Output
输出一行两个整数M和S。
设\(f(i,j)\)表示以\((i,j)\)为左上角的正方形内出现过的数值的种类数,则M表示f的最大值,S表示f的总和。
Sample Input
3 5 2
1 5 3 3 3
4 1 3 3 4
4 2 4 4 3
Sample Output
4 20
分析
正方形求并问题,考虑扫描线
因为边长为给定的,所以每个正方形进入和离开扫描线的时候最多只会改变扫描线一个区间的状态
求这个区间的端点,需要在扫描线上查前驱和后继,用线段树维护
这题鬼畜地卡常,然后模仿ccz大佬加入了一些鬼畜的优化才卡过
code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define u32 unsigned int
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
using namespace std;
inline ll read(){
ll f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//**********head by yjjr**********
#define ctz(x) __builtin_ctz(x)
#define clz(x) (31^__builtin_clz(x))
#define inf 1e5
const u32 A=-1,maxn=1e5+6,maxm=3e3+6;
u32 bs[maxm][2][maxm/32+6],t0[maxn][4],t1[maxn][maxm/32+6];
int n,m,k,mx,a[maxm][maxm],s[maxm][maxm],pv[maxn];ll 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;}
void cal(int x,int y,int w,int val){
int L=-inf,R=inf,p1=y>>5,p2=y>>10,p3;u32 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 rep(i,p2+1,2)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 dep(i,p2-1,0)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]+=val,s[x][R]-=val;
}
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);
}
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()
{
n=read(),m=read(),k=read();
rep(i,1,n)rep(j,1,m)a[i][j]=read();
rep(j,1,m){
rep(i,1,n){
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;
}
rep(i,1,n)pv[a[i][j]]=0;
}
rep(i,1,n)rep(j,1,m){
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]);
}
rep(i,1,n){
rep(j,1,m)s[i][j]+=s[i][j-1];
rep(j,1,m)s[i][j]+=s[i-1][j];
if(i>=k)rep(j,k,m)sum+=s[i][j],mx=max(s[i][j],mx);
}
cout<<mx<<' '<<sum<<endl;
return 0;
}