P8472 [Aya Round 1 G] 咕噜论坛(post)

题目链接

1|0Problem

给定一个矩阵,最多进行 k 次操作,每次可以把 B 改成 GG 改成 BP 不能改,问最后能得到的最大的颜色相同的子矩阵。

2|0Solution

由于 n,m500,所以应该是一个 O(n3) 的做法。

我们枚举一个矩阵的最上行 x,最下行 y,最左列和最右列的指针分别为 L=1,R=1,这是就确定了一个矩阵,由于具有单调性,所以我们可以每次判断如果能够在 k 次操作内将其改成相同矩阵(前缀和预处理),就可以考虑将矩阵加大即 R++,否则 L++。注意如果当前只有一列,且不合法,并不代表后面也不合法,需要 L,R 都向后推一列。

注意对于每一个 x,y 都有最大的 L,R,所以开数组存下这个 L,R,然后你需要记录最大的矩阵面积。

有个坑点,要注意紫名矩阵也算,方法一样。

3|0Code

细节较多,码风较丑,仅供参考。

#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; }

__EOF__

本文作者JMartin
本文链接https://www.cnblogs.com/LAK666/p/16564836.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   Epoch_L  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示