CF1720E Misha and Paintings 题解

· · 题解

Codeforces Round #815 (Div. 2) 全场题解以及更好的阅读体验

记原始矩阵中不同值的个数为 m

每次只要选中一个 1\times 1 的小矩阵改变值即可,最小操作次数为 k-m

样例以及手玩似乎答案不超过 2?考虑证明。

我们构造出一种两次一定能解决的方案。

不妨让第一次选中的正方形左上角为原矩阵左上角,假设我们能增加长度 L 就增加,并且此矩形的颜色我们不统计上,即颜色为剩下 k 个之一,不增加颜色。

也就是说,我们选择了最大的 L 使得 m'\ge mL 再增加 1 就会使 m'<m

我们考虑第二个矩形,将它的右下角置于 (L+1,L+1),向左上扩展,颜色与第一个矩形相同,都不对整体做贡献。

可以发现,每当第二个矩形边长多 1 就会多两个格子消失,最多消失两种颜色,所以可以通过此将颜色变到 kk-1

m'=k 时,已满足要求;当 m'=k-1 时,我们可以将第二个矩形的颜色换成一种新的颜色,将 m' 增加 1,使其等于 k

这样我们就证明了最多两次。

我们考虑什么时候答案为 1,其余时候都为 2

先计算出每个颜色的上界 (x1,y1),下界 (x2,y2)。即 (x_1,y_1),(x2,y2) 是满足能覆盖此种颜色的最小子矩阵。

枚举一个正方形的边长 len,然后枚举左上角 (i,j),记 c[i][j] 为当边长为 len 左上角为 (i,j) 时,能覆盖的颜色个数。

考虑如何计算 c[i][j],直接算复杂度太高,考虑每个颜色的贡献。

对于一种颜色 ,通过它的上下界可以计算出在哪一个区域内的点以 len 为边长得到正方形可以覆盖这种颜色。

我们通过二维差分加二维前缀和解决 c 的计算。

最后我们只需要判断每一个点 (i,j) 在长为 len 的前提下计算出的 m-c[i][j] 是否等于 kk-1 即可。

```cpp #include<bits/stdc++.h> using namespace std; inline int read(){ int x=0,f=1; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-')f=-1; c=getchar(); } while(c<='9'&&c>='0'){ x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return x*f; } void print(int x){ if(x<0)putchar('-'),x=-x; if(x>9)print(x/10); putchar(x%10^48); } const int N=505; int n,k,a[N][N],c[N][N],m; struct node{ int x1,y1,x2,y2; }b[N*N]; int main(){ n=read(),k=read(); for(int i=1;i<=n*n;++i)b[i].x1=b[i].y1=1e9; for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ a[i][j]=read(); b[a[i][j]].x1=min(b[a[i][j]].x1,i); b[a[i][j]].y1=min(b[a[i][j]].y1,j); b[a[i][j]].x2=max(b[a[i][j]].x2,i); b[a[i][j]].y2=max(b[a[i][j]].y2,j); } } for(int i=1;i<=n*n;++i)if(b[i].x1!=1e9)m++; if(m<=k){print(k-m);return 0;} for(int len=1;len<=n;++len){ memset(c,0,sizeof(c)); for(int i=1;i<=n*n;++i){ if(b[i].x1==1e9)continue; int X1=max(1,b[i].x2-len+1); int Y1=max(1,b[i].y2-len+1); int X2=min(n-len+1,b[i].x1); int Y2=min(n-len+1,b[i].y1); if(X1<=X2&&Y1<=Y2){ c[X1][Y1]++; c[X2+1][Y1]--; c[X1][Y2+1]--; c[X2+1][Y2+1]++; } } for(int i=1;i<=n;++i){ for(int j=1;j<=n;++j){ c[i][j]+=c[i-1][j]+c[i][j-1]-c[i-1][j-1]; if(m-c[i][j]==k||m-c[i][j]==k-1){ puts("1");return 0; } } } } puts("2"); return 0; } ```