题目链接
http://acm.hdu.edu.cn/showproblem.php?pid=5696
解题思路
大致思路:
找到区间[l,r]的最小值的位置p,确定了区间[l,r]的最小值为a[p],那么区间[l,r]内包含p点的任意子区间都要通过a[p]去乘以某个此子区间的最大值得到此子区间价值吧。
很显然,value[p,i]=max(value[p,j],a[p]*a[j+1])
,
解释一下,假设p<j,那么由于所有区间的最小值都是a[p],那么区间价值只取决于最大值的大小,而位于p同侧的大区间的价值比小区间的价值大,要么相等;(你想想是不是)
更新完以区间[l,r]中最小值为分界点的ans之后,分别对p的左、右半区间递归。
AC代码
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+100; ll tmp[N],a[N],ans[N]; int n; void dfs(int L,int R){ if(L>R) return ; int pos=L; ll maxx=0; for(int i=1;i<=R-L+1;i++) tmp[i]=0; //初始化tmp数组为0 for(int i=L;i<=R;i++) if(a[pos]>a[i]) pos=i;//找到区间[l,r]中最小值的位置 for(int i=L;i<=pos;i++) tmp[pos-i+1]=max(tmp[pos-i+1],a[pos]*a[i]); //tmp的索引为区间长度,pos左半区间每个位置的值乘上区间[l,r]的最小值。此式中取最大值操作的意义与直接赋值含义相同。 for(int i=pos;i<=R;i++) tmp[i-pos+1]=max(tmp[i-pos+1],a[pos]*a[i]);//pos的右半区间,每个位置的值乘上区间[l,r]的最小值,同时tmp取同区间长度下较大的乘积。 for(int i=1;i<=R-L+1;i++){ maxx=max(maxx,tmp[i]);//小区间的tmp最大值如果比大区间的tmp最大值还大,让大区间的最大值也等于小区间的最大值。//比较精髓的地方 ans[i]=max(ans[i],maxx);//刷新最终的区间最大值 } dfs(L,pos-1);//去掉pos点,找左半区间的最小值再进行上述操作。 dfs(pos+1,R);//去掉pos点,找右半区间的最小值再进行上述操作。 return ; } int main(){ while(cin>>n){ memset(ans,0,sizeof ans); memset(a,0,sizeof a); for(int i=1;i<=n;i++) cin>>a[i]; dfs(1,n); for(int i=1;i<=n;i++) cout<<ans[i]<<endl; } }