hdu5696-分治-暴力剪枝-rmq-dfs-单调栈-区间的价值
来源:互联网 发布:esxi添加网络文件系统 编辑:程序博客网 时间:2024/06/06 07:41
http://acm.hdu.edu.cn/showproblem.php?pid=5696
后几个写法慢慢写。
开始写了一个暴力,一直tle,应该是边界没处理好。尴尬。。
我们可以确定一种情况。
除却相等使用的情况。最小的那个数作为区间中的最小数,越少越好,而最大数,越多越好
两个贪心策略:尽可能的用最大这个数。(枚举区间情况)
2 同一个 最大*最小 可以被很多长度区间所利用(包含区间情况)
。暴力 虽然是枚举的最大值,但是这个最大值是可以被好几个 区间所利用的,。所以可以。
#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>using namespace std;typedef long long ll;const int maxn=100050;ll dp[maxn];ll a[maxn];int main(){ int m; while(~scanf("%d",&m)){ for(int i=1;i<=m;i++) scanf("%lld",&a[i]); memset(dp,0,sizeof(dp)); for(int i=1;i<=m;i++){ int l=i; int r=i; dp[1]=max(dp[1],a[i]*a[i]); ll min1=a[i]; while(1){ if(a[l]>a[i]||a[r]>a[i]) break; if((r-l+1)==m) break; if((a[l-1]>a[r+1]||(r==m))&&1!=l) {min1=min(a[l-1],min1);l--;} else {min1=min(a[r+1],min1);r++;} dp[r-l+1]=max(dp[r-l+1],a[i]*min1); } } for(int i=1;i<=m;i++) printf("%lld\n",dp[i]); } return 0;}
但是单调栈我就要说一下了
这个是用的单调栈+rmq(st算法倍增)来弄得。
特别注明一下 单调栈,
维护一个单调递增的栈,用来确定i为最小来确定的区间,这个可以当做模板使用。可以自己想一下。
先维护每个i为最小的区间,然后在这个区间内用rmq求极大值,相乘就行了,注意 开头我说的第二项原理,并且第二项原理是可以从1用到m的。自己一下就明白了。
那为什么这个题不用枚举每一个为最大值,然后rmq求极小值,然后在正常搞呢。
我试着写了一下,mb竟然不对。大概是因为 最大值只能利用一次。
(恩,最大值被多次利用有两种情况,一种是第一种计算区间的时候,第二种是区间包含的情况。)
我说的不太明白,慢慢我会补几张图的,
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<string>#include<vector>#include <ctime>#include<queue>#include<set>#include<map>#include<cmath>#include <bits/stdc++.h>typedef long long ll;/*我们可以确定一种情况。除却相等使用的情况。最小的那个数作为区间中的最小数,越少越好,而最大数,越多越好两个贪心策略:尽可能的用最大这个数。2 同一个 最大*最小 可以被很多长度区间所利用*/using namespace std;const int maxn=100005;int l[maxn];int r[maxn];stack<pair<int,ll> >q;ll a[maxn];ll FMax[maxn][20];int m;ll dp[maxn];void Init(){ int i,j; for(i=1;i<=m;i++) FMax[i][0]=a[i];//以i为起点,长度为1的区间,初始值为a[i]; for(i=1;(1<<i)<=m;i++){ //区间慢慢扩增 for(j=1;j+(1<<i)-1<=m;j++){ //区间起点, // FMin[j][i]=min(FMin[j][i-1],FMin[j+(1<<(i-1))][i-1]); FMax[j][i]=max(FMax[j][i-1],FMax[j+(1<<(i-1))][i-1]); } }}ll Query(int l,int r){ int k=(int)(log(r-l+1)/log(2)); return max(FMax[l][k],FMax[r-(1<<k)+1][k]);//0(1)的查询}int main(){ while(~scanf("%d",&m)){ memset(dp,0,sizeof(dp)); memset(FMax,0,sizeof(FMax)); memset(a,0,sizeof(a)); memset(l,0,sizeof(l)); memset(r,0,sizeof(r)); for(int i=1;i<=m;i++){ scanf("%lld",&a[i]); } while(!q.empty()) q.pop(); q.push(make_pair(0,0)); for(int i=1;i<=m;i++){ while(!q.empty()){ pair<int,ll> u=q.top(); if(u.second>a[i]){ r[u.first]=i-1; q.pop(); } else { q.push(make_pair(i,a[i])); break; } } } while(!q.empty()){ pair<int,ll>u=q.top(); r[u.first]=m; q.pop(); } q.push(make_pair(0,0)); for(int i=m;i>=1;i--){ while(!q.empty()){ pair<int,ll> u=q.top(); if(u.second>a[i]){ l[u.first]=i+1; q.pop(); } else { q.push(make_pair(i,a[i])); break; } } } while(!q.empty()){ pair<int,ll>u=q.top(); l[u.first]=1; q.pop(); } /*for(int i=1;i<=m;i++){ printf("%d %d\n",l[i],r[i]); }*/ Init(); for(int i=1;i<=m;i++){ int len=r[i]-l[i]+1; dp[len]=max(dp[len],Query(l[i],r[i])*a[i]); } dp[m+1]=0; ll ans=0; for(int i=m;i>=1;i--){ ans=max(dp[i+1],ans); dp[i]=max(dp[i],ans); } for(int i=1;i<=m;i++){ printf("%lld\n",dp[i]); } } return 0;}
最后的写法是 分治。有空多看
#include<iostream> #include<cstdio> #include<cstring> #define LL long long using namespace std; const int MAXN = 1e5+5; LL a[MAXN],temp[MAXN],ans[MAXN]; void solve(int l,int r) { if(l>r) return ; int p=0; for(int i = l;i<=r;i++) { if(!p||a[i]<a[p]) p = i; } int w = r-l+1; for(int i = 1;i<=w;i++) temp[i] = 0; LL pre = 0; //遍历一遍区间获得他们的最大区间值 for(int i = p-1;i>=l;i--) { if(temp[p-i+1]<max(pre,(LL)a[p]*a[i])) { temp[p-i+1] = max(pre,(LL)a[p]*a[i]); //因为最小值固定下来了,也就是看最大值哪个大 //短区间的值可以给长区间做更新(也就是短区间的最大值更大) pre=temp[p-i+1]; } } pre = 0; for(int i = p+1;i<=r;i++) { if(temp[i-p+1]<max(pre,(LL)a[p]*a[i])) { temp[i-p+1] = max(pre,(LL)a[p]*a[i]); pre = temp[i-p+1]; } } ans[1] = max(ans[1],a[p]*a[p]); pre = 0; //整体的区间长度的最大价值更新操作 for(int i = 2;i<=w;i++) { if(ans[i]<max(pre,temp[i])) { ans[i]=max(pre,temp[i]); } pre = max(pre,temp[i]); } solve(l,p-1); solve(p+1,r); } int main() { freopen("in2.txt","r",stdin); //freopen("out1.txt","w",stdout); int n; while(~scanf("%d",&n)) { memset(ans,0,sizeof(ans)); for(int i = 0;i<MAXN;i++) temp[i] = 0; for(int i =1;i<=n;i++) scanf("%I64d",&a[i]); solve(1,n); for(int i = 1;i<=n;i++) { printf("%I64d\n",ans[i]); } } return 0; }
阅读全文
0 0
- hdu5696-分治-暴力剪枝-rmq-dfs-单调栈-区间的价值
- HDU5696 区间的价值(分治/单调队列)
- 分治法 区间的价值 hdu5696
- HDU5696:区间的价值(搜索 & 分治 & 思维)
- [HDU 5696] 区间的价值 (单调栈+RMQ)
- 区间顺序枚举 hdu5696 区间的价值
- 百度之星初赛B hdu5696 区间的价值 分治思想
- Hdu5696 区间的价值(花式水)
- HDU5696 2016百度之星初赛Astar Round2B 区间的价值
- HDU5696(分治)
- hdu 区间的价值(RMQ+扫描)
- HDU 5696 区间的价值 (DFS)
- HDU-5696-区间的价值(DFS)
- 51nod 1564 && 1674 区间的价值(V2) 数列分治
- 51nod 1674 区间的价值 V2(分治)
- 51nod 1674 区间的价值 V2(暴力)
- 单调栈/单调队列/RMQ
- poj 3714 Raid【(暴力+剪枝) || (分治法+剪枝)】
- kotlin 基本语法(五)
- 《MyBatis 从入门到精通》转发送书~~~
- [2017雅礼集训6-28]T2 jump
- 架构师需要直面的几个问题
- [UVA10003] 切木棍(dp)
- hdu5696-分治-暴力剪枝-rmq-dfs-单调栈-区间的价值
- eclipse 中修改提示框(alt+/)背景色或文字颜色
- 入职两周心得体会
- Android 仿美图秀秀颜色混合
- 建造者模式
- 创建爬虫----遍历单个域名爬取赶集网
- h5学习笔记:标签页 after
- mciSendString的介绍
- Mysql技术内幕InnoDB存储引擎读书笔记--《四》表