题解:SP6517 JOCHEF - Farmer Sepp
一眼简单悬线法,而且有多倍经验,感觉这题被遗忘了,那我就拿下这个水紫吧!
我们用 a 数组表示能向上延伸能到达的最大距离,依次遍历每一行,如果该位置为 F,他可以从上一行转移过来,将a数组增加一,如果该位置为 C,意味着这个位置不能成矩形,将 a 数组变为 0。
接下来进行悬线法的标准操作,设 l 数组为能向左延伸到不低于此位置的高度的最远位置,然后进行推导。
-
当 \(i=1\),到达边界停止。
-
当 \(a[i]>a[i-1]\),低于高度,停止拓展。
-
当 \(a[i]<=a[i-1]\),可以扩展,直接继承 \(l[i]=l[l[i]-1]\)。
r 数组则是向右延伸,相同方法赋值即可,最后统计答案直接将高度乘上可延伸的长度,结果取最大值一气呵成。
运行过程类似下图(其他题的图片但同一个意思)。
注意这题有多组数据,换行与多测清空都要注意。
上代码!!!
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e4+10;
#define int ll
int n,m,k;
int a[N];
int l[N],r[N];
int ans;
signed main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
while(1){
cin>>n>>m;
if(n==m&&n==0){
break;
}
ans=0;
memset(a,0,sizeof a);
cin>>k;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
l[j]=r[j]=j;
}
char c;
for(int j=1;j<=m;j++){
cin>>c;
if(c=='C'){
a[j]=0;
}
else if(c=='H'){
a[j]++;
}
}
for(int j=1;j<=m;j++){
while(l[j]!=1&&a[j]<=a[l[j]-1]){
l[j]=l[l[j]-1];
}
}
for(int j=m;j>=1;j--){
while(r[j]!=m&&a[j]<=a[r[j]+1]){
r[j]=r[r[j]+1];
}
}
for(int j=1;j<=m;j++){
ans=max(ans,a[j]*(r[j]-l[j]+1));
}
}
cout<<(ll)ans*k<<"\n";
}
return 0;
}