[arc067F]Yakiniku Restaurants[矩阵差分]
Description
Solution
假如我们确定了烧烤店区间[l,r],则票j必定会选择在B[i][j](l<=i<=r)最大的烧烤店使用。
反过来想,我们想要票j在第i个烧烤店使用,寻找可行区间[L,R]。
为了避免重复计算,我们钦定$k\epsilon [L,i]$时B[k][j]<B[i][j],$k\epsilon [i,R]$时B[k][j]<=B[i][j]。
接下来我们构造一个矩阵,矩阵的横坐标代表可行区间的左端点L,纵坐标表示可行区间的右端点R,对矩阵进行差分。使得当查询到子矩阵(L[i],i)-(i,R[i])时答案会加上B[i][j]。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> using namespace std; typedef long long ll; int n,m,A[5010],B[5010][210]; ll matrix[5010][5010];int l[5010],r[5010]; int st[5010],tp; ll sum[5010]; int main() { scanf("%d%d",&n,&m); for (int i=2;i<=n;i++) {scanf("%d",&A[i]);sum[i]=sum[i-1]+A[i];} for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) scanf("%d",&B[i][j]); for (int j=1;j<=m;j++) { tp=0; for (int i=1;i<=n;i++) { while (tp&&B[i][j]>B[st[tp]][j]) r[st[tp--]]=i-1; st[++tp]=i; } while (tp) r[st[tp--]]=n; tp=0; for (int i=n;i;i--) { while(tp&&B[i][j]>=B[st[tp]][j]) l[st[tp--]]=i+1; st[++tp]=i; } while (tp) l[st[tp--]]=1; for (int i=1;i<=n;i++) { matrix[i+1][r[i]+1]+=B[i][j]; matrix[l[i]][i]+=B[i][j]; matrix[l[i]][r[i]+1]-=B[i][j]; matrix[i+1][i]-=B[i][j]; } } ll ans=0; for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { matrix[i][j]+=matrix[i-1][j]+matrix[i][j-1]-matrix[i-1][j-1]; if (i<=j) ans=max(ans,matrix[i][j]-(sum[j]-sum[i])); } cout<<ans; }