题目大意:给你一个n*n的矩阵,现在问对于每个kle n,求出所有k*k的子矩阵中,元素种类数不超过q的矩阵个数,nle 1500, qle 10
先考虑最暴力的做法:
对于每个格子,求出以它为子矩阵右下角时,左上角能到达的最远位置,时间O(n^{4})。再统计起来跑个后缀和
考虑可以$n^{3}$时的做法:
双指针对一条斜线上的格子进行维护,暴力进行指针移动时的更新
虽然双指针是一种优化递推,但其并没有利用q=10的性质
考虑直接递推
我们从左到右再从上到下依次处理每个点
对于每个格子维护一个vector,记录从它开始,不断向左上拓展时,第一次出现某个元素的相对位置信息
比如
1 2 3 ...
1 5 3 ...
1 2 3 ...
...
现在要处理(3,3)位置上的那个3
那么它相对于(3,3)的位置就是(3,3),中间的5相对位置是(2,2)。
5下面的2相对位置也是(2,2),因为如果想在(3,3)把这个2框进去,左上角一定会拓展到(2,2)
5上面的2相对位置是(1,1),但可惜在记录的时候我们只记录第一次出现的位置
我们最多只需要记录q+1个元素,第q+1个元素往右下一格就是答案
当前格子左,上,左上的三个相邻格子都是已知信息,取出来排序,再依次选第一次出现的位置
但左和上取出来时相对位置可能会改变
画图发现,这与元素在倒L形的左侧一列/上侧一行的出现情况有关,额外记录元素在这个倒L形左列/上行的出现情况,再进行大讨论即可转移
直接做会被卡空间,滚动数组就好
1 int T,n,q; 2 int a[N1][N1],sum[N1][N1]; 3 struct node{ 4 int x,y,val; bool tp,le; 5 }; 6 int cmp(node &s1,node &s2) 7 { 8 return s1.x+s1.y>s2.x+s2.y; 9 } 10 11 int ans[N1]; 12 int now,pst; 13 vector<node>to[N1][N1]; 14 node se[50]; 15 int tot; 16 17 void addnode(int x,int y,int nx,int ny) 18 { 19 int m; node k; 20 if(x==nx-1&&y==ny-1) 21 { 22 m=to[pst][y].size(); 23 for(int i=0;i<m;i++) 24 { 25 k=to[pst][y][i]; se[tot++]=k; 26 // se[tot++]=(node){k.x,k.y,k.val,k.tp.k.le}; 27 } 28 } 29 if(x==nx-1&&y==ny) 30 { 31 m=to[pst][y].size(); 32 for(int i=0;i<m;i++) 33 { 34 k=to[pst][y][i]; 35 if(x==k.x&&y==k.y){ 36 if(y>1) k.y--; else continue; 37 k.le=0; k.tp=1; 38 }else if(!k.tp){ 39 k.x++; k.tp=(a[k.x][k.y]==k.val)?1:0; k.le=1; 40 }else{ 41 if(k.y>1) k.y--; else continue; // 后续与左侧取并!! 42 k.le=(a[k.x][k.y]==k.val)?1:0; 43 } 44 se[tot++]=k; 45 } 46 } 47 if(x==nx&&y==ny-1) 48 { 49 m=to[now][y].size(); 50 for(int i=0;i<m;i++) 51 { 52 k=to[now][y][i]; 53 if(x==k.x&&y==k.y){ 54 k.x--; 55 k.le=1; k.tp=0; 56 }else if(!k.le){ 57 k.y++; k.le=(a[k.x][k.y]==k.val)?1:0; k.tp=1; 58 }else{ 59 if(k.x>1) k.x--; else continue; // 后续与上侧取并!! 60 k.tp=(a[k.x][k.y]==k.val)?1:0; 61 } 62 se[tot++]=k; 63 } 64 } 65 } 66 void solve(int x,int y) 67 { 68 tot=0; se[tot++]=(node){x,y,a[x][y],1,1}; 69 addnode(x-1,y,x,y); 70 if(y>1) addnode(x-1,y-1,x,y), addnode(x,y-1,x,y); 71 sort(se,se+tot,cmp); node k; int fl; 72 for(int i=0;i<tot;i++) 73 { 74 k=se[i]; fl=0; 75 for(int j=0;j<to[now][y].size();j++) 76 { 77 if(to[now][y][j].val==k.val) 78 { 79 if(to[now][y][j].x==k.x && to[now][y][j].y==k.y) 80 to[now][y][j].tp|=k.tp, to[now][y][j].le|=k.le; 81 fl=1; break; 82 } 83 } 84 if(!fl) 85 { 86 to[now][y].push_back(k); 87 if(to[now][y].size()==q+1) break; 88 } 89 } 90 int m=to[now][y].size(); 91 // sum[x][y]=x-to[now][y][m-1].x+1; 92 if(m==q+1) sum[x][y]=x-to[now][y][m-1].x; 93 else sum[x][y]=min(x,y); 94 } 95 96 int ret[N1]; 97 int main() 98 { 99 // freopen("a.txt","r",stdin); 100 freopen("a.in","r",stdin); 101 // srand(time(NULL)); 102 scanf("%d%d",&n,&q); 103 for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) read(a[i][j]); 104 now=1, pst=0; 105 for(int j=1;j<=n;j++) 106 { 107 to[0][j].push_back( (node){1,j,a[1][j],1,1} ); 108 sum[1][j]=1; 109 } 110 for(int i=2;i<=n;i++) 111 { 112 for(int j=1;j<=n;j++) 113 { 114 to[now][j].clear(); 115 solve(i,j); 116 } 117 swap(now,pst); 118 } 119 for(int i=1;i<=n;i++) 120 { 121 for(int j=1;j<=n;j++) 122 { 123 ret[1]++; ret[sum[i][j]+1]--; 124 // printf("%d ",sum[i][j]); 125 } 126 // puts(""); 127 } 128 for(int i=1;i<=n;i++) ret[i]=ret[i-1]+ret[i]; 129 for(int i=1;i<=n;i++) printf("%d ",ret[i]); 130 return 0; 131 }