您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: