P8472 [Aya Round 1 G] 咕噜论坛(post)
Problem
给定一个矩阵,最多进行 \(k\) 次操作,每次可以把 B
改成 G
,G
改成 B
,P
不能改,问最后能得到的最大的颜色相同的子矩阵。
Solution
由于 \(n,m\le500\),所以应该是一个 \(O(n^3)\) 的做法。
我们枚举一个矩阵的最上行 \(x\),最下行 \(y\),最左列和最右列的指针分别为 \(L=1,R=1\),这是就确定了一个矩阵,由于具有单调性,所以我们可以每次判断如果能够在 \(k\) 次操作内将其改成相同矩阵(前缀和预处理),就可以考虑将矩阵加大即 \(R++\),否则 \(L++\)。注意如果当前只有一列,且不合法,并不代表后面也不合法,需要 \(L,R\) 都向后推一列。
注意对于每一个 \(x,y\) 都有最大的 \(L,R\),所以开数组存下这个 \(L,R\),然后你需要记录最大的矩阵面积。
有个坑点,要注意紫名矩阵也算,方法一样。
Code
细节较多,码风较丑,仅供参考。
#include<bits/stdc++.h>
using namespace std;
#define int long long
void read(int &x)
{
char ch=getchar();
int r=0,w=1;
while(!isdigit(ch))w=ch=='-'?-1:1,ch=getchar();
while(isdigit(ch))r=(r<<3)+(r<<1)+(ch^48),ch=getchar();
x=r*w;
}
const int N=507;
char c[N][N];
int sumb[N][N],sumg[N][N],l[N][N],r[N][N],ans[N][N],anss[N][N],ls[N][N],rs[N][N],ss[N][N];
bool ok=0;
int queryb(int a,int b,int c,int d)
{
return sumb[c][d]-sumb[c][b-1]-sumb[a-1][d]+sumb[a-1][b-1];
}
int queryg(int a,int b,int c,int d)
{
return sumg[c][d]-sumg[c][b-1]-sumg[a-1][d]+sumg[a-1][b-1];
}
main()
{
int n,m,k;
read(n);read(m);read(k);
for(int i=1;i<=n;i++)
scanf("%s",c[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
sumb[i][j]=sumb[i-1][j]+sumb[i][j-1]-sumb[i-1][j-1]+(c[i][j]=='B');
sumg[i][j]=sumg[i-1][j]+sumg[i][j-1]-sumg[i-1][j-1]+(c[i][j]=='G');
// cout<<sumb[i][j]<<" "<<sumg[i][j]<<endl;
}
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
int L=1,R=1;
while(L<=R&&R<=m)
{
// cout<<L<<" "<<R<<endl;
int s=ans[i][j];
if((R-L+1)*(j-i+1)-queryb(i,L,j,R)-queryg(i,L,j,R)!=0)
{
L++;
if(L>R&&R<m)R++;
continue;
}
if(min(queryb(i,L,j,R),queryg(i,L,j,R))<=k)
{
ans[i][j]=max(ans[i][j],(R-L+1)*(j-i+1));
if(ans[i][j]>s)l[i][j]=L,r[i][j]=R;R++;
// printf("ans[%d][%d]=%d,l=%d,r=%d\n",i,j,ans[i][j],l[i][j],r[i][j]);
}
else L++;
if(L>R&&R<m)R++;
}
}
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
int L=1,R=1;
while(L<=R&&R<=m)
{
int s=anss[i][j];//cout<<L<<" "<<R<<" "<<(R-L+1)*(j-i+1)-queryb(i,L,j,R)-queryg(i,L,j,R)<<endl;
if(queryb(i,L,j,R)+queryg(i,L,j,R)==0)
{
anss[i][j]=max(anss[i][j],(R-L+1)*(j-i+1));
if(anss[i][j]>s)ls[i][j]=L,rs[i][j]=R;
R++;
}
else
{
L++;
if(L>R&&R<m)R++;
continue;
}if(L>R&&R<m)R++;
}
}
int sb=0,ansi,ansj;
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
{
if(sb<ans[i][j])
{
ok=0;
sb=ans[i][j];
ansi=i,ansj=j;
}
if(sb<anss[i][j])
{
sb=anss[i][j];
ok=1;
}
}
cout<<sb<<endl;
//cout<<ansi<<" "<<ansj<<endl;
if(ok)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i>=ansi&&i<=ansj&&j>=ls[ansi][ansj]&&j<=rs[ansi][ansj])
cout<<"P";
else cout<<c[i][j];
}
cout<<endl;
}
return 0;
}
if(queryb(ansi,l[ansi][ansj],ansj,r[ansi][ansj])<=k)
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i>=ansi&&i<=ansj&&j>=l[ansi][ansj]&&j<=r[ansi][ansj])
cout<<"G";
else cout<<c[i][j];
}
cout<<endl;
}
}
else
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i>=ansi&&i<=ansj&&j>=l[ansi][ansj]&&j<=r[ansi][ansj])
cout<<"B";
else cout<<c[i][j];
}
cout<<endl;
}
}
return 0;
}