标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 15396 Accepted Submission(s): 4470
#include<stdio.h> #include<iostream> #include<string.h> #include<math.h> #include<algorithm> using namespace std; const int N = 100005; int min_dp[N][30]; long long a[N]; int L[N],R[N]; int MIN(int i,int j) { if(a[i]>a[j]) return j; return i; } void init_RMQ(int n) { for(int i=1; i<=n; i++) { min_dp[i][0]=i; } for(int j=1; (1<<j)<=n; j++) { for(int i=1; i+(1<<j)-1<=n; i++) { min_dp[i][j] = MIN(min_dp[i][j-1],min_dp[i+(1<<(j-1))][j-1]); } } } int MIN_RMQ(int l,int r) { int k=0; while((1<<(k+1))<=(r-l+1)) k++; return MIN(min_dp[l][k],min_dp[r-(1<<k)+1][k]); } int binary(int value,int l,int r) ///找到最右边 { while(l<=r) { if(l==r) return l; int mid = (l+r)>>1; if(value<=a[MIN_RMQ(l,mid)]) { l = mid+1; } else r = mid; } } int binary2(int value,int l,int r) ///找到最左边 { while(l<r) { if(l==r-1){ ///防止死循环,这里弄了好久 if(a[r]<value) return r; ///如果在r 并且a[r]<value 那么肯定r就是左边界
return l; } int mid = (l+r)>>1; if(value<=a[MIN_RMQ(mid,r)]) { r = mid-1; } else l = mid; } return l; } int main() { int n; while(scanf("%d",&n)!=EOF&&n) { for(int i=1; i<=n; i++) { scanf("%lld",&a[i]); } init_RMQ(n); L[1]=1; R[n]=n; for(int i=1; i<=n; i++) { if(i!=n) { R[i] = binary(a[i],i+1,n); if(R[i]==n&&a[i]<=a[n]); else R[i]--; } if(i!=1) { L[i] = binary2(a[i],1,i-1); if(L[i]==1&&a[i]<=a[1]); else L[i]++; } } long long mx = -1; for(int i=1; i<=n; i++) { if((R[i]-L[i]+1)*a[i]>mx) mx = (R[i]-L[i]+1)*a[i]; } printf("%lld\n",mx); } }
解法二:DP 时间复杂度O(n*k) k是个很小的数
#include <stdio.h> #include <iostream> #include <string.h> #include <math.h> #include <algorithm> using namespace std; const int N = 100005; long long a[N],L[N],R[N]; ///L[i]记录i点能够到达最左边的位置,R[i]同理 int main() { int n; while(scanf("%d",&n)!=EOF&&n){ for(int i=1;i<=n;i++){ scanf("%lld",&a[i]); } L[1]=1; R[n]=n; for(int i=2;i<=n;i++){ ///先求出每个坐标最左边能到达的位置 int t = i; while(t>1&&a[i]<=a[t-1]){ t = L[t-1]; ///这步相当巧妙,直接实现了跳转,如果a[t-1]不小于a[i] ///的话,我们可以断定a[t-1]的最左边肯定包含a[i]的最左边.直接跳过中间的点 ///时间复杂度就肯定没有O(n*n)了,应该是O(n*k) k是个比较小的数 } L[i] = t; } for(int i=n-1;i>=1;i--){ ///找最右边 int t =i; while(t<n&&a[i]<=a[t+1]){ t = R[t+1]; } R[i] = t; } long long mx = -1; for(int i=1;i<=n;i++){ if((R[i]-L[i]+1)*a[i]>mx) mx = (R[i]-L[i]+1)*a[i]; } printf("%lld\n",mx); } return 0; }
标签:
原文地址:http://www.cnblogs.com/liyinggang/p/5383514.html