Hihocoder1673
这个题还是挺有意思的,得发现点性质,然后才能知道要怎么搞。
首先我们得知道这个合法段是连一起的,这个是一个很重要的一点,我们得知道如果10101010 可以,那么他的所有子段都是可以的。。。。。。。
这个应该是很好发现的? (那怎么才能发现这一点呢??????) 我们首先应该对单行分析,分析一下单行怎么搞,因为单行是矩阵的基础,然后考虑先填1010,这样搞,发现这个段的性质 这个手玩一下样例就可以了,很好发现的
(事实证明手玩样例是很重要的,很多题目都是手玩样例出来的)
这个的话我们可以通过手玩确定出来很好的性质,比如那道cf 的 d和这道
然后我们可以通过预处理知道当前这个点向上能衍生的最长长度的长度
然后根据上面的性质分成一个个的段,然后再这个段里面通过单调栈操作
下面是代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 #include <cmath> 6 #include <bitset> 7 #include <stack> 8 typedef long long ll; 9 using namespace std; 10 const int maxn=2100; 11 int n,m; 12 char s[maxn][maxn]; 13 int h[maxn][maxn]; 14 int li[maxn][maxn]; 15 int siz[maxn]; 16 stack<int> sta; 17 int main(){ 18 scanf("%d%d",&n,&m); 19 for(int i=1;i<=n;i++) scanf("%s",s[i]+1); 20 for(int i=1;i<=n;i++){ 21 for(int j=1;j<=m;j++){ 22 if(i==1) h[i][j]=1; 23 else{ 24 if(s[i][j]!=s[i-1][j]) h[i][j]=h[i-1][j]+1; 25 else h[i][j]=1; 26 } 27 } 28 } 29 30 int ans=0; 31 for(int i=1;i<=n;i++){ 32 int l,r; 33 for(int j=1;j<=m;j=r+1){ 34 l=j;r=j; 35 for(int k=j+1;k<=m;k++){ 36 if(s[i][k]!=s[i][k-1]) r=k; 37 } 38 for(int k=l;k<=r;k++) li[i][k]=h[i][k],siz[k]=1; 39 li[i][r+1]=0;li[i][l-1]=0; 40 while(!sta.empty()) sta.pop(); 41 sta.push(l-1); 42 for(int k=l;k<=r+1;k++){ 43 if(li[i][k]>=li[i][sta.top()]){ 44 sta.push(k); 45 }else{ 46 int len=0; 47 while(!sta.empty()&&li[i][k]<li[i][sta.top()]){ 48 len+=siz[sta.top()]; 49 ans=max(ans,len*li[i][sta.top()]); 50 sta.pop(); 51 } 52 sta.push(k);siz[k]+=len; 53 } 54 } 55 } 56 } 57 printf("%d\n",ans); 58 return 0; 59 }