zoukankan      html  css  js  c++  java
  • Codeforces 1500D

    Codeforces 题面传送门 & 洛谷题面传送门

    首先先讲一发我的 (n^2qlog n) 的做法,虽然没有付诸实现并且我也深知它常数巨大过不去,但是我还是决定讲一讲(大雾

    考虑设 (f(i,j)) 表示以 (i,j) 为左上角,满足其中不同颜色个数 (le q) 的子正方形中大小最大的那个的边长,那么显然求出 (f(i,j)) 后一遍后缀和即可求出答案。于是问题转化为如何求 (f(i,j))。注意到一个显然的结论:(f(i,j)ge f(i,j-1)-1),故考虑用类似双针的方法求解,我们对于每一行动态地维护一个 (len) 表示当前子正方形的边长,每次将 (len)(1) 并检验当前子正方形是否可行,如果不可行那么将 (len)(1)break,此时的 (len) 值就是我们要求的 (f(i,j)),并再将 (len) 减一并考虑下一个格子 (f(i,j+1)),不难发现 (len) 最多变化 (mathcal O(n)) 次,因此我们下面需考虑当 (len) 增大或减小时不同颜色个数的变化。注意到每次 (len)(1) 等价于以下两个操作:

    • 将某行 (x) 上的 (l,l+1,l+2,cdots,r) 格子加入当前图形
    • 将某列 (x) 上的 (l,l+1,l+2,cdots,r) 格子加入当前图形

    (len) 减一也同理。考虑怎样处理这个加入某行/某列的格子的操作,注意到 (q) 最多只有 (10),因此如果新加入的格子中不同颜色个数 (>10) 就肯定不合法了,这部分我们就对行/列分别双针预处理一遍,即对于每一个格子 ((i,j)) 找出最大的 (r) 满足 ((i,j),(i,j+1),cdots,(i,r)) 中不同颜色个数 (le q),以及最大的 (r) 满足 ((i,j),(i+1,j),cdots,(r,j)) 中不同颜色个数 (le q),这样即可判断新加入的格子中不同颜色个数是否 (le q),否则我们暴力枚举新加入的格子中不同颜色更新桶即可,计算某个颜色在新加入的格子中出现次数可用二分。枚举新加入的格子中不同的颜色的过程就在之前双针的过程中,额外记录下当前遍历到的不同颜色有哪些即可。时间复杂度 (n^2qlog n),稳了(指 T 稳了)


    接下来就是正解了,我们考虑对于每个格子 ((i,j)) 求出以它为右下角,且不同颜色个数 (le q) 的最大正方形的边长,考虑怎样暴力求之——我们考察每个在该点左上方出现的颜色,对于每一种颜色我们求出该颜色的点与 ((i,j)) 切比雪夫距离的最小值 (d),显然如果子正方形要包含该颜色,那么该子正方形边长必须 (ge d+1),因此我们找出第 (q+1) 大的 (d),显然子正方形边长必须 (<d),否则子正方形中至少有 (q+1) 种颜色,而如果 (d-1lemin(i,j)),一定存在一个以 ((i,j)) 为右下角的边长为 (d-1) 的正方形,答案就是 (d-1),否则答案为 (min(i,j))

    考虑如何求 (q+1) 大的 (d),对于每一个点我们建立三个长度 (q+1) 的数组 (L_{i,j},U_{i,j},LU_{i,j}) 分别表示 ((i,j)) 左方、上方、左上方出现过的、距离 ((i,j))(q+1) 大的颜色,按照它们对应的 (d) 值从小到大排序。(L_{i,j}) 的求法是容易的,直接从 (L_{i,j-1}) 加一个点继承过来即可,(U_{i,j}) 也同理。至于 (LU_{i,j}),不难发现在 (LU_{i,j}) 出现过的颜色,必然在 (L_{i,j},U_{i-1,j},LU_{i-1,j-1}) 中至少一者出现过,因此我们把这三个数组看作一个队列,每次取出队首最小的元素即可在 (mathcal O(q)) 时间内求出这三个数组。

    时间复杂度 (n^2q)

    正解题解长度小于歪解是啥操作

    const int MAXN=1500;
    int n,c,a[MAXN+5][MAXN+5],cnt[MAXN+5],vis[MAXN*MAXN+5];
    struct dat{
    	short int x,y;
    	dat(short int _x=0,short int _y=0):x(_x),y(_y){}
    	int col(){return a[x][y];}
    };
    int getdis(int x1,int y1,int x2,int y2){return max(x1-x2,y1-y2);}
    dat L[MAXN+5][MAXN+5][12],U[MAXN+5][MAXN+5][12],LU[MAXN+5][MAXN+5][12];
    int sL[MAXN+5][MAXN+5],sU[MAXN+5][MAXN+5],sLU[MAXN+5][MAXN+5];
    int main(){
    	scanf("%d%d",&n,&c);
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) scanf("%d",&a[i][j]);
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
    		L[i][j][++sL[i][j]]=dat(i,j);
    		for(int k=1;k<=sL[i][j-1];k++){
    			if(L[i][j-1][k].col()==a[i][j]) continue;
    			if(sL[i][j]<=c) L[i][j][++sL[i][j]]=L[i][j-1][k];
    		}
    		U[i][j][++sU[i][j]]=dat(i,j);
    		for(int k=1;k<=sU[i-1][j];k++){
    			if(U[i-1][j][k].col()==a[i][j]) continue;
    			if(sU[i][j]<=c) U[i][j][++sU[i][j]]=U[i-1][j][k];
    		}
    		for(int p1=1,p2=1,p3=1;(p1<=sL[i][j]||p2<=sU[i-1][j]||p3<=sLU[i-1][j-1])&&sLU[i][j]<=c;){
    			int mn1=INF,mn2=INF,mn3=INF;
    			while(p1<=sL[i][j]&&vis[L[i][j][p1].col()]) ++p1;
    			while(p2<=sU[i-1][j]&&vis[U[i-1][j][p2].col()]) ++p2;
    			while(p3<=sLU[i-1][j-1]&&vis[LU[i-1][j-1][p3].col()]) ++p3;
    			if(p1<=sL[i][j]) mn1=getdis(i,j,L[i][j][p1].x,L[i][j][p1].y);
    			if(p2<=sU[i-1][j]) mn2=getdis(i,j,U[i-1][j][p2].x,U[i-1][j][p2].y);
    			if(p3<=sLU[i-1][j-1]) mn3=getdis(i,j,LU[i-1][j-1][p3].x,LU[i-1][j-1][p3].y);
    			int mn=min(mn1,min(mn2,mn3));
    			if(mn==INF) break;
    			if(mn==mn1) LU[i][j][++sLU[i][j]]=L[i][j][p1],vis[L[i][j][p1++].col()]=1;
    			else if(mn==mn2) LU[i][j][++sLU[i][j]]=U[i-1][j][p2],vis[U[i-1][j][p2++].col()]=1;
    			else LU[i][j][++sLU[i][j]]=LU[i-1][j-1][p3],vis[LU[i-1][j-1][p3++].col()]=1;
    		}
    		for(int k=1;k<=sLU[i][j];k++) vis[LU[i][j][k].col()]=0;
    	}
    	for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){
    		int d=(sLU[i][j]==c+1)?getdis(i,j,LU[i][j][c+1].x,LU[i][j][c+1].y):INF;
    		chkmin(d,min(i,j));
    //		printf("%d %d %d
    ",i,j,d);
    		cnt[d]++;
    	}
    	for(int i=n;i;i--) cnt[i]+=cnt[i+1];
    	for(int i=1;i<=n;i++) printf("%d
    ",cnt[i]);
    	return 0;
    }
    
  • 相关阅读:
    关键字搜索.sql
    加载SOS调试器扩展
    数字转换成十六进制.sql
    复制指定节点及其所有子节点到指定结点的处理示例(借鉴方式排序法).sql
    字符串并集&交集处理示例.sql
    使用UNION实现库存报表的示例.sql
    Shell脚本学习笔记[1]
    bash中cut命令的用法[转]
    xargs的用法[转]
    正则语言学习笔记
  • 原文地址:https://www.cnblogs.com/ET2006/p/Codeforces-1500D.html
Copyright © 2011-2022 走看看