CF1500D Tiles for Bathroom
一开始想的是顺序枚举左上角,然后算出以为左上角的最小右下角答案。然而下一步直接死掉,根本没得做。他不像CF1396D点的个数只有2000,可以扫两维,每次移动扫描线只是单点修改。这个不行。
然后瞄了一眼题解发现这玩意其实有,就是考虑包含关系。但是暴力扩展我依然不会做。就是说从一个位置扩展到新的位置,新的东西永远都是没处理过的,或者没法预处理的。
枚举左上角会有这种问题,那改成右下角就不一样了,(顺序枚举右下角等于换种顺序枚举另外3个角)因为枚举到的时候,没处理过的点只有一个。然后冷静考虑枚举右下角需要维护什么,就是求最大的左上角。
考虑一维的情况怎么处理,就是枚举右端点,求上一个和他之间有种颜色的位置。可以考虑维护个下标表示离他最近的个颜色最后出现的位置。每向右挪一个,都会往里考虑加一个点,直接插入或者替换一个即可,都是插在队尾。
二维情况类似,右端点->右下角,下标->横纵坐标,最近距离->最近切比雪夫距离。别的一样。
而且要注意是从和两条转移过来。只有从到的时候,队列里的点到当前右下角的切比雪夫距离的相对大小关系是不变的。归并一下即可。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long ll;
#define N 1504
struct node{int x,y;}c[N][N][13],cc[13];
int n,q,a[N][N],le[N][N][13],up[N][N][13],tc[13],tl[N][N],tu[N][N],tot[N][N];
bool vis[N*N];
int ans[N];
inline void rd(int &x)
{
x=0;register char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){x=x*10+c-48;c=getchar();}
}
int main()
{
rd(n),rd(q);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)rd(a[i][j]);
for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
{
for(int ii=1;ii<=tl[i][j-1];ii++)tc[ii]=le[i][j-1][ii];
tl[i][j]=tl[i][j-1];bool flag=false;
for(int ii=1;ii<=tl[i][j];ii++)if(a[i][tc[ii]]==a[i][j])
{
for(int jj=ii;jj<tl[i][j];jj++)tc[jj]=tc[jj+1];
tc[tl[i][j]]=j;flag=true;break;
}
if(!flag)
{
if(tl[i][j]==q+1){for(int ii=1;ii<tl[i][j];ii++)tc[ii]=tc[ii+1];tl[i][j]--;}
tc[++tl[i][j]]=j;
}for(int ii=1;ii<=tl[i][j];ii++)le[i][j][ii]=tc[ii];
}
for(int j=1;j<=n;j++)for(int i=1;i<=n;i++)
{
for(int ii=1;ii<=tu[i-1][j];ii++)tc[ii]=up[i-1][j][ii];
tu[i][j]=tu[i-1][j];bool flag=false;
for(int ii=1;ii<=tu[i][j];ii++)if(a[tc[ii]][j]==a[i][j])
{
for(int jj=ii;jj<tu[i][j];jj++)tc[jj]=tc[jj+1];
tc[tu[i][j]]=i;flag=true;break;
}
if(!flag)
{
if(tu[i][j]==q+1){for(int ii=1;ii<tu[i][j];ii++)tc[ii]=tc[ii+1];tu[i][j]--;}
tc[++tu[i][j]]=i;
}for(int ii=1;ii<=tu[i][j];ii++)up[i][j][ii]=tc[ii];
}
for(int i=1;i<=n;i++)
{tot[1][i]=tl[1][i];
for(int ii=1;ii<=tl[1][i];ii++)c[1][i][ii]=(node){1,le[1][i][ii]};
ans[1]++;
}
for(int i=2;i<=n;i++)
{tot[i][1]=tu[i][1];
for(int ii=1;ii<=tu[i][1];ii++)c[i][1][ii]=(node){up[i][1][ii],1};
ans[1]++;
}
for(int i=2;i<=n;i++)for(int j=2;j<=n;j++)
{
int z1=tot[i-1][j-1],z2=tu[i][j],z=1;
while(z1&&z2&&z<=q+1)
{
if(vis[a[c[i-1][j-1][z1].x][c[i-1][j-1][z1].y]]){z1--;continue;}
if(vis[a[up[i][j][z2]][j]]){z2--;continue;}
int d1=max(i-c[i-1][j-1][z1].x,j-c[i-1][j-1][z1].y);
int d2=i-up[i][j][z2];
if(d1<d2)cc[z++]=c[i-1][j-1][z1--];
else cc[z++]=(node){up[i][j][z2--],j};
vis[a[cc[z-1].x][cc[z-1].y]]=1;
}
while(z1&&z<=q+1)
{
if(vis[a[c[i-1][j-1][z1].x][c[i-1][j-1][z1].y]]){z1--;continue;}
cc[z++]=c[i-1][j-1][z1--];
vis[a[cc[z-1].x][cc[z-1].y]]=1;
}
while(z2&&z<=q+1)
{
if(vis[a[up[i][j][z2]][j]]){z2--;continue;}
cc[z++]=(node){up[i][j][z2--],j};
vis[a[cc[z-1].x][cc[z-1].y]]=1;
}
tot[i][j]=z-1;
for(int ii=1;ii<z;ii++)c[i][j][ii]=cc[ii];
for(int ii=1;ii<z;ii++)vis[a[c[i][j][ii].x][c[i][j][ii].y]]=0;
reverse(c[i][j]+1,c[i][j]+tot[i][j]+1);
z1=tot[i][j],z2=tl[i][j-1],z=1;
while(z1&&z2&&z<=q+1)
{
if(vis[a[c[i][j][z1].x][c[i][j][z1].y]]){z1--;continue;}
if(vis[a[i][le[i][j-1][z2]]]){z2--;continue;}
int d1=max(i-c[i][j][z1].x,j-c[i][j][z1].y);
int d2=j-le[i][j-1][z2];
if(d1<d2)cc[z++]=c[i][j][z1--];
else cc[z++]=(node){i,le[i][j-1][z2--]};
vis[a[cc[z-1].x][cc[z-1].y]]=1;
}
while(z1&&z<=q+1)
{
if(vis[a[c[i][j][z1].x][c[i][j][z1].y]]){z1--;continue;}
cc[z++]=c[i][j][z1--];
vis[a[cc[z-1].x][cc[z-1].y]]=1;
}
while(z2&&z<=q+1)
{
if(vis[a[i][le[i][j-1][z2]]]){z2--;continue;}
cc[z++]=(node){i,le[i][j-1][z2--]};
vis[a[cc[z-1].x][cc[z-1].y]]=1;
}
tot[i][j]=z-1;
for(int ii=1;ii<z;ii++)c[i][j][ii]=cc[ii];
reverse(c[i][j]+1,c[i][j]+1+tot[i][j]);
for(int ii=1;ii<z;ii++)vis[a[c[i][j][ii].x][c[i][j][ii].y]]=0;
//printf("%d %d:\n",i,j);
//for(int ii=1;ii<=tot[i][j];ii++)printf("(%d %d)",c[i][j][ii].x,c[i][j][ii].y);puts("");
if(tot[i][j]<=q)ans[min(i,j)]++;
else
{
int te=max(i-c[i][j][1].x,j-c[i][j][1].y);
ans[min(min(i,j),te)]++;
}
}
for(int i=n;i;i--)ans[i]+=ans[i+1];
for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下