区间的价值
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Problem Description
我们定义“区间的价值”为一段区间的最大值*最小值。
一个区间左端点在L,右端点在R,那么该区间的长度为(R−L+1)。
现在聪明的杰西想要知道,对于长度为k的区间,最大价值的区间价值是多少。
当然,由于这个问题过于简单。
我们肯定得加强一下。
我们想要知道的是,对于长度为1∼n的区间,最大价值的区间价值分别是多少。
样例解释:
长度为1的最优区间为2−2 答案为6∗6
长度为2的最优区间为4−5 答案为4∗4
长度为3的最优区间为2−4 答案为2∗6
长度为4的最优区间为2−5 答案为2∗6
长度为5的最优区间为1−5 答案为1∗6
Input
多组测试数据
第一行一个数n(1≤n≤100000)。
第二行n个正整数(1≤ai≤109),下标从1开始。
由于某种不可抗力,ai的值将会是1∼109内<b style="color:red;">随机产生</b>的一个数。(除了样例)
Output
输出共n行,第i行表示区间长度为i的区间中最大的区间价值。
Sample Input
5
1 6 2 4 4
Sample Output
36
16
12
12
6
Source
2016"百度之星" - 初赛(Astar Round2B)
思路:利用单调栈得到以a[i]为最小值的区间左端点和右端点;
发现a[i]*该区间的最大值,为该区间的最小值;
举个例子;
5
1 6 2 4 4
以2为区间最小值,该区间为[2,5];
在[2,5]区间长度为4,发现在这区间内长度为3,2,1都比2*6=12大;
#include<bits/stdc++.h> using namespace std; #define ll long long #define mod 100000007 #define esp 0.00000000001 const int N=1e5+10,M=1e6+10,inf=1e9+10; ll sum[N<<2]; ll a[N<<2]; int d[N]; int l[N]; int r[N]; ll ans[N]; void build(int l,int r,int pos) { if(l==r) { sum[pos]=a[l]; return; } int mid=(l+r)>>1; build(l,mid,pos<<1); build(mid+1,r,pos<<1|1); sum[pos]=max(sum[pos<<1],sum[pos<<1|1]); } ll query(int L,int R,int l,int r,int pos) { if(L<=l&&R>=r) return sum[pos]; int mid=(l+r)>>1; ll ans=0; if(R>mid)ans=max(ans,query(L,R,mid+1,r,pos<<1|1)); if(L<=mid)ans=max(ans,query(L,R,l,mid,pos<<1)); return ans; } int main() { int x,y,z,i,t; while(~scanf("%d",&x)) { memset(ans,0,sizeof(ans)); for(i=1;i<=x;i++) scanf("%I64d",&a[i]); build(1,x,1); a[0]=a[x+1]=0; int k=0; d[++k]=0; for(i=1;i<=x;i++) { while(a[d[k]]>=a[i])k--; l[i]=d[k]; d[++k]=i; } k=0; d[++k]=x+1; for(i=x;i>=1;i--) { while(a[d[k]]>=a[i])k--; r[i]=d[k]; d[++k]=i; } for(i=1;i<=x;i++) ans[r[i]-l[i]-1]=max(ans[r[i]-l[i]-1],(ll)query(l[i]+1,r[i]-1,1,x,1)*a[i]); for(i=x-1;i>=1;i--) ans[i]=max(ans[i],ans[i+1]); for(i=1;i<=x;i++) printf("%I64d\n",ans[i]); } return 0; }
时间: 2024-10-20 18:52:27