HDU 5696 区间的价值
区间的价值
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1341 Accepted Submission(s): 600
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
一个区间左端点在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>的一个数。(除了样例)
第一行一个数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
Recommend
思路:
首先回顾一下快排的思想:快排每次划分,都是从随机找一个值作为阀值(简单起见,通常找第一个),然后从需要划分的区间的最右端找比阀值小的值,用这个值去填最左端那个位置,从最左端找比阀值大的值,用这个值填最右端那个位置,交替去找,知道low和high相等,然后将阀值放到该位置,这次划分结束,阀值左边的值都比阀值右边的值要小。递归排序阀值左边的区间和右边的区间,最终保证有序。
用一颗线段树维护某一段区间中的最小最大值的编号。
这个题目要求的是区间长度为i的区间中最小值和最大值的乘积的最大值。我们拿到一段区间l, r,假设这段区间中的最小值的位置为idmin,最大值的位置为idmax,这段区间中的所有区间长度大于等于abs(idmin-idmax)+1的区间都可以被a[idmin]*a[idmax]更新到,由于我们要的是最大值,所以我们以最小值为分隔,递归求解左部分和右部分,都不能包含分隔。
错因:
long long tmp=1ll*num[minn]*num[maxn];没有强制转化为long long
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 100001 using namespace std; int n,num[MAXN]; struct nond{ int minn,maxn,l,r; }tree[MAXN*4]; long long ans[MAXN]; void up(int now){ if(num[tree[now*2].maxn]>num[tree[now*2+1].maxn]) tree[now].maxn=tree[now*2].maxn; else tree[now].maxn=tree[now*2+1].maxn; if(num[tree[now*2].minn]<num[tree[now*2+1].minn]) tree[now].minn=tree[now*2].minn; else tree[now].minn=tree[now*2+1].minn; } void build(int now,int l,int r){ tree[now].l=l;tree[now].r=r; if(l==r){ tree[now].minn=l; tree[now].maxn=l; return ; } int mid=(tree[now].l+tree[now].r)/2; build(now*2,l,mid); build(now*2+1,mid+1,r); up(now); } int query(int now,int l,int r,int opt){ if(tree[now].l==l&&tree[now].r==r){ if(opt==0) return tree[now].maxn; else if(opt==1) return tree[now].minn; } int mid=(tree[now].l+tree[now].r)/2; if(r<=mid) return query(now*2,l,r,opt); else if(l>mid) return query(now*2+1,l,r,opt); else{ if(opt==0){ if(num[query(now*2,l,mid,opt)]>num[query(now*2+1,mid+1,r,opt)]) return query(now*2,l,mid,opt); else return query(now*2+1,mid+1,r,opt); } else{ if(num[query(now*2,l,mid,opt)]<num[query(now*2+1,mid+1,r,opt)]) return query(now*2,l,mid,opt); else return query(now*2+1,mid+1,r,opt); } } } void dfs(int l,int r,int now){ if(r<l) return ; int maxn=query(1,l,r,0); int minn=query(1,l,r,1); if(maxn>minn) swap(minn,maxn); long long tmp=1ll*num[minn]*num[maxn]; for(int i=minn-maxn+1;i<=r-l+1;i++) ans[i]=max(ans[i],tmp); if(num[minn]>num[maxn]){ dfs(l,maxn-1,now); dfs(maxn+1,r,now); } else{ dfs(l,minn-1,now); dfs(minn+1,r,now); } } int main(){ while(scanf("%d",&n)!=EOF){ memset(tree,0,sizeof(tree)); memset(ans,0,sizeof(ans)); for(int i=1;i<=n;i++) scanf("%d",&num[i]); build(1,1,n); dfs(1,n,n); for(int i=1;i<=n;i++) cout<<ans[i]<<endl; } return 0; }
细雨斜风作晓寒。淡烟疏柳媚晴滩。入淮清洛渐漫漫。
雪沫乳花浮午盏,蓼茸蒿笋试春盘。人间有味是清欢。