Codeforces Round #343 (Div. 2) D. Babaei and Birthday Cake
2016-02-27 17:07
357 查看
题意:有几个蛋糕,要求把他们按照这样的方式堆起来:
下面的编号比上面的小;下面的体积比上面的小。
求把这些蛋糕堆起来能得到的最大体积是多少。
思路:
首先,一定要排序。按照编号排还是按照体积排?
题目中输入顺序就是按照编号排序的。先考虑按照编号排序。对于每个i,要找到j小于i,且V(j) < V(i)中总体积最大的j,然后到i的最优解就是j的最优解加上V(i)。
初步看上去,好像是dp。
如果每次找j用扫描的办法,可以解决问题,但是复杂度是n方的。
如果每次不用扫描,用线段树来保存从1到i的最大值,这样复杂度世够了,但是无法保证V(j) < V(i)。
按照编号排序貌似不行,但是感觉就差一点点。
换成按照体积排序。这样,我们每次选择到蛋糕一定能满足V(j) < V(i),而且用线段树很容易求出1到i中的最优解,这样两个条件就都能满足了。
因为题目要求V(j)严格小于V(i),所以排序的时候,对于相等的体积,序号小的要放后面。
官方给出题解的译文:
首先,我们计算每个蛋糕的体积: vi=π∗hi∗r2i
现在,考虑序列 v1,v2,v3,…,vn :问题的答案是这个序列中递增子序列的最大和。我们怎么样解决它?首先去掉小数,我们可以定义一个新的数组 a1,a2,a3,…,an,ai=vi/π=hi∗r2i
我们考虑 dpi 是以 ai 结束的序列和的最大值且
dpi=max(ai,maxj<i,aj≤aidp[j]+ai)
这个问题的答案就是: π∗maxi=1tondp[i]
现在,我们怎么计算 dpi=max(ai,maxj<i,aj≤aidp[j]+ai) ?我们使用一个线段树,这个线段树有两种操作:1.将第i个数更改为v;2.找出1到i中最大的数。
现在,我们将dp与线段树结合寻找答案。
假设 a1,a2,a3,…,an 已经排序好了。我们定义 bi是ai 的位置。现在填充 dpi ,我们找出区间 [1,bi] 中最大的, 设为x,然后将线段树中 bi 个位置设置成 ai+x 。问题的答案就是区间[1,n]中的最大值。
时间复杂度: O(nlogn)
代码如下:
下面的编号比上面的小;下面的体积比上面的小。
求把这些蛋糕堆起来能得到的最大体积是多少。
思路:
首先,一定要排序。按照编号排还是按照体积排?
题目中输入顺序就是按照编号排序的。先考虑按照编号排序。对于每个i,要找到j小于i,且V(j) < V(i)中总体积最大的j,然后到i的最优解就是j的最优解加上V(i)。
初步看上去,好像是dp。
如果每次找j用扫描的办法,可以解决问题,但是复杂度是n方的。
如果每次不用扫描,用线段树来保存从1到i的最大值,这样复杂度世够了,但是无法保证V(j) < V(i)。
按照编号排序貌似不行,但是感觉就差一点点。
换成按照体积排序。这样,我们每次选择到蛋糕一定能满足V(j) < V(i),而且用线段树很容易求出1到i中的最优解,这样两个条件就都能满足了。
因为题目要求V(j)严格小于V(i),所以排序的时候,对于相等的体积,序号小的要放后面。
官方给出题解的译文:
首先,我们计算每个蛋糕的体积: vi=π∗hi∗r2i
现在,考虑序列 v1,v2,v3,…,vn :问题的答案是这个序列中递增子序列的最大和。我们怎么样解决它?首先去掉小数,我们可以定义一个新的数组 a1,a2,a3,…,an,ai=vi/π=hi∗r2i
我们考虑 dpi 是以 ai 结束的序列和的最大值且
dpi=max(ai,maxj<i,aj≤aidp[j]+ai)
这个问题的答案就是: π∗maxi=1tondp[i]
现在,我们怎么计算 dpi=max(ai,maxj<i,aj≤aidp[j]+ai) ?我们使用一个线段树,这个线段树有两种操作:1.将第i个数更改为v;2.找出1到i中最大的数。
现在,我们将dp与线段树结合寻找答案。
假设 a1,a2,a3,…,an 已经排序好了。我们定义 bi是ai 的位置。现在填充 dpi ,我们找出区间 [1,bi] 中最大的, 设为x,然后将线段树中 bi 个位置设置成 ai+x 。问题的答案就是区间[1,n]中的最大值。
时间复杂度: O(nlogn)
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; typedef long long ll; const double PI = acos(-1); struct Cake{ ll V; int id; bool operator < (const Cake a) const { if(V != a.V) return V<a.V; return id>a.id; } }cake[100005]; ll dp[400005]; int p;ll v; void update(int l,int r,int o){ if(l == r){ dp[o] = v;return; } int m = (l+r)/2; if(p<=m)update(l,m,o*2); else update(m+1,r,o*2+1); dp[o] = max(dp[o*2],dp[o*2+1]); } int ql,qr; ll query(int l,int r,int o){ if(l>=ql && r <= qr)return dp[o]; ll ret = 0; int mid = (l+r)/2; if(ql <= mid) ret = max(ret,query(l,mid,o*2)); if(qr > mid) ret = max(ret,query(mid+1,r,o*2+1)); return ret; } int main() { // freopen("data.txt","r",stdin); memset(dp,0,sizeof(dp)); int n; scanf("%d",&n); for(int i = 1; i<= n; ++i){ ll r,h; scanf("%lld%lld",&r,&h); cake[i].V = r * r * h; cake[i].id = i; } sort(cake+1,cake+n+1); for(int i = 1; i <= n ; ++i ){ ql = 1;qr = cake[i].id; v = query(1,n,1) + cake[i].V; p = cake[i].id; update(1,n,1); } ql = 1;qr = n; ll ans = query(1,n,1) ; printf("%.6lf\n", ans * PI); return 0; }
相关文章推荐
- android多语言切换
- 通过汇编一个简单的C程序,分析汇编代码理解计算机是如何工作的
- 道客巴巴免费复制
- 线程结束的正确方式
- Java集群--大型网站是怎样解决多用户高并发访问的
- io流处理文件夹复制功能(java代码)
- springMVC对异常处理的支持
- Linux精讲——chattr特殊权限
- springMVC对异常处理的支持
- 常用网址
- 排序之冒泡排序
- Python中的模块
- 项目管理模式之如何去除SVN标记
- 机房重构之窗体登录
- 非参方法-K NearestNeighbor(KNN)
- typeid typeinfo
- 【leetcode】Array——Search a 2D Matrix(74)
- C语言:未包含头文件引起的奇怪错误
- 文本深度表示模型Word2Vec
- Android 高清加载巨图方案 拒绝压缩图片