codeforces 319C div1 189
2016-07-25 15:42
316 查看
题目链接
http://codeforces.com/contest/319/problem/C
题意:给你一个n表示有n棵树,第一棵树高度一定为1,往后高度一定递增。然后有一个b数组。减少任意一颗树的高度1的话费是b[i],那么a[i]一定等于0,并且a[j]>0,j>i。
这个dp不是很明显。因为第一棵树高度为1,肯定首先砍掉,通过样例我们发现砍第一次不需要cost,于是先砍掉树1。往后的时候比较容易想到,要么就一直砍完,要么这棵树不砍(贪心)。因为题目要求必须全部砍完,然而b
又等于0,因此只需要把第n颗树砍完,那么之后花费都是0了。
通过这样我们很容易得到一个dp方程了,dp[i]表示砍掉第i颗树的最小花费,那么有dp[i]=mindp[j]+a[i]∗b[j]这里a递增,b递减。这样是n方的方程。
变形一下,有dp[j]=a[i]∗(−b[j])+dp[i])
dp[j],−b[j]都是之前已经算好的状态,我们可以把二者合为一个点Point(−b[j],dp[j])为什么把b[j]取成负数?因为我们让点集的x坐标递增容易推到之后的公式。这样可以建立坐标系
设k=a[i],x=−b[j],c=dp[i],y=dp[j]那么原式变成y=k∗x+c要求c的最小值,相当于一条直线从c为−inf一直往上扫,直到遇到我们存好的第一个状态点.
用一个队列来维护之前的点集,就像下凸包一样,同时保证最左边的两个点斜率都大于a[i],这样每次那最左边的一个点更新dp[i]便完全没问题了。这个题要注意一下,不能把斜率判断拆开乘,会爆long long,此处我直接double判断斜率
// // Created by Running Photon // Copyright (c) 2015 Running Photon. All rights reserved. // #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <sstream> #include <set> #include <vector> #include <stack> #define ALL(x) x.begin(), x.end() #define INS(x) inserter(x, x,begin()) #define ll long long #define CLR(x) memset(x, 0, sizeof x) using namespace std; const int inf = 0x3f3f3f3f; const int MOD = 1e9 + 7; const int maxn = 1e5 + 10; const int maxv = 1e3 + 10; const double eps = 1e-9; ll a[maxn], b[maxn]; ll dp[maxn]; #define x first #define y second typedef pair <ll, ll> sta; sta que[maxn]; int main() { #ifdef LOCAL freopen("C:\\Users\\Administrator\\Desktop\\in.txt", "r", stdin); freopen("C:\\Users\\Administrator\\Desktop\\out.txt","w",stdout); #endif // ios_base::sync_with_stdio(0); int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%lld", &a[i]); } for(int i = 1; i <= n; i++) { scanf("%lld", &b[i]); } memset(dp, 0x3f, sizeof dp); dp[1] = 0; int head = 0, tail = 0; que[tail].x = -b[1]; que[tail++].y = dp[1]; for(int i = 2; i <= n; i++) { while(head + 1 < tail && a[i] * (que[head+1].x - que[head].x) > que[head+1].y - que[head].y) head++; dp[i] = que[head].y - a[i] * que[head].x; sta u = sta(-b[i], dp[i]); while(head + 1 < tail) { ll ly = (que[tail-1].y-que[tail-2].y); ll lx = (que[tail-1].x-que[tail-2].x); ll ry = (u.y-que[tail-1].y); ll rx = (u.x-que[tail-1].x); double k1 = 1.0 * ly / lx; double k2 = 1.0 * ry / rx; if(k1 < k2 - eps) break; tail--; } que[tail++] = u; } printf("%lld\n", dp ); return 0; }
相关文章推荐
- 二叉树中序遍历变型——折纸问题
- POJ 2386 Lake Counting
- 爹地,我找到了!,15个极好的Linux find命令示例
- 在开启DRS的集群中修复VMware虚拟主机启动问题
- nginx + tomcat 架构中,error_page错误页面的设置
- host文件设置详解
- SQL清除表格内容
- Android Studio Preview ”Rendering Problems“问题解决初探。
- PARDISO 5.0.0 Solver Project
- hdu5001 walk 【概率dp】
- 探索Javascript异步编程
- linux手贱操作
- 【Android之实践】monkeyrunner采用对象id,进行UI自动化操作
- hibernate注解整理
- leetcode 123. Best Time to Buy and Sell Stock III
- C++ PDFLib 8.0 中文输出
- Node.js EventEmitter
- virsh - brctl - common networking configurations used by libvirt
- spring中用p标签配置bean的属性
- POJ1002:487-3279 神奇的TLE