【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp

题目描述

给出 $(2n+1)\times (2n+1)$ 个点,点 $(i,j)$ 的权值为 $a[max(|i-n-1|,|j-n-1|)]$ ,找一条从 $(1,1)$ 走到 $(2n+1,2n+1)$ 的路径,使得经过的点(包括起点和终点)权值和最小。求这个权值和。

输入

第一行一个正整数 $n$ 。

第二行 $n+1$ 个正整数 $a[0],a[1],…,a[n]$ ,表示从内到外每层的中继器的延时值。

输出

输出一行一个数表示改造后的最短引爆时间。

样例输入

9
9 5 3 7 6 9 1 8 2 4

输出

69



题解

CDQ分治+斜率优化dp

我tm就是个傻逼 = =  明明正解就一个贪心我非要写dp+斜率优化。。。

显然所选路径具有对称性,并且是从左上角走到 $(i,i),i\le n+1$ ,然后沿着这个等距离圈走到 $(2n+2-i,2n+2-i)$ ,再按照同样的路径返回。

设 $f[i]$ 表示到点 $(i+1,i+1)$ 的最小代价。

设 $b[i]=a[n-1-i]$ (为了方便从外层向内层递推)

正解:从 $i$ 到 $i+1$ 显然是通过 $1~i$ 中最小的那一层向右平移的,因此 $f[i]=f[i-1]+b[i]+\text{max}_{j=0}^{i-1}b[j]$ ,边界条件 $f[0][0]=b[0]$。

时间复杂度 $O(n)$

我的解法:考虑从 $(j,j)$ 先横着走到 $(j,i)$ 再走到 $(i,i)$ 的过程,那么有:$f[i]=\text{max}_{j=0}^{i-1}(f[j]+\sum\limits_{k=j+1}^ib[k]+(i-j)·b[i])$.

前缀相减得 $f[i]=f[j]+sum[i]-sum[j]+(i-j)·b[j]$ 。

移项得 $j·b[j]+sum[j]-f[j]=i·b[j]+sum[i]-f[i]$ 。

容易发现可以斜率优化,要求截距得最大值,维护上凸壳。

但是这里的横坐标 $b[j]$ 不单调,因此无法使用单调数据结构维护,因此使用CDQ分治。

时间复杂度 $O(n\log n)$

不管了反正过去了。。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
typedef long long ll;
ll a[N] , sum[N] , f[N];
int id[N] , t[N] , sta[N];
inline ll y(int i) {return a[i] * i + sum[i] - f[i];}
inline ll x(int i) {return a[i];}
inline long double slop(int a , int b) {return (long double)(y(b) - y(a)) / (x(b) - x(a));}
void solve(int l , int r)
{
	if(l == r)
	{
		id[l] = l;
		return;
	}
	int mid = (l + r) >> 1 , i , j , k;
	solve(l , mid);
	for(k = 0 , i = l ; i <= mid ; i ++ )
	{
		while(k && x(sta[k]) == x(id[i])) k -- ;
		while(k > 1 && slop(sta[k] , id[i]) <= slop(sta[k - 1] , sta[k])) k -- ;
		sta[++k] = id[i];
	}
	for(j = 1 , i = mid + 1 ; i <= r ; i ++ )
	{
		while(j < k && slop(sta[j] , sta[j + 1]) >= i) j ++ ;
		f[i] = min(f[i] , f[sta[j]] + a[sta[j]] * (i - sta[j]) + sum[i] - sum[sta[j]]);
	}
	solve(mid + 1 , r);
	for(i = j = l , k = mid + 1 ; i <= r ; i ++ )
	{
		if(k > r || (j <= mid && (x(id[j]) == x(id[k]) ? y(id[j]) < y(id[k]) : x(id[j]) < x(id[k])))) t[i] = id[j ++ ];
		else t[i] = id[k ++ ];
	}
	for(i = l ; i <= r ; i ++ ) id[i] = t[i];
}
int main()
{
	int n , i;
	ll ans = 1ll << 62;
	scanf("%d" , &n);
	for(i = n ; ~i ; i -- ) scanf("%lld" , &a[i]) , sum[i] = a[i];
	for(i = 1 ; i <= n ; i ++ ) sum[i] += sum[i - 1];
	memset(f , 0x3f , sizeof(f));
	f[0] = a[0] , solve(0 , n);
	for(i = 0 ; i <= n ; i ++ )
		ans = min(ans , 2 * f[i] + (4 * (n - i) - 1) * a[i]);
	printf("%lld\n" , ans);
	return 0;
}

原文地址:https://www.cnblogs.com/GXZlegend/p/8241854.html

时间: 2024-10-18 02:21:08

【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp的相关文章

BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以在第D天花费P的费用(当然,前提是你有至少P元)租借这台机器,从第D+1天起,操作机器将为你产生每天G的收益.在你不再需要机器时,可以将机器卖掉,一次性获得R的收益.厂房里只能停留一台机器.不能在购买和卖出机器的那天操作机器,但是可以在同一天卖掉一台机器再买入一台.在第N+1天,你必须卖掉手上的机器

BZOJ 1492 NOI 2007 货币兑换Cash CDQ分治+斜率优化DP

题目大意:有两种金券,A和B.每一天有一个rate值,表示购入的比例:还有每一天AB金券的售价.现在给出初始的钱数,问最后能够获得多少钱. 思路:这算是神题了吧,啃论文啃别人代码将近一天才算有点明白. 首先题目中说的可以买一部分或者卖一部分是扯淡的,因为为了最大获利一定要全部买入,全部卖出.朴素的DP方程就好弄了. 设f[i]为第i天最多的B券的数量.那么f[i] = (rate[j] * f[j] * a[i] + f[j] * b[i]) / (rate[i] * a[i] + b[i])

bzoj1492[NOI2007]货币兑换Cash cdq分治+斜率优化dp

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 5541  Solved: 2228[Submit][Status][Discuss] Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金

bzoj3672/luogu2305 购票 (运用点分治思想的树上cdq分治+斜率优化dp)

我们都做过一道题(?)货币兑换,是用cdq分治来解决不单调的斜率优化 现在它放到了树上.. 总之先写下来dp方程,$f[i]=min\{f[j]+(dis[i]-dis[j])*p[i]+q[i]\} ,j是i的祖先,dis[i]-dis[j]<=l[i]$ ,其中dis[i]表示1号点到i号点的距离 可以很明显的看出斜率优化,但我们要放到树上做 于是就运用点分治的思想来找重心(正如普通的cdq是找重点一样) 步骤是这样的: 1.对于根为x的一个子树,我们先找到它的重心rt 2.把rt的子树刨掉

[BZOJ 1492][NOI2007]货币兑换Cash(CDQ分治+斜率优化Dp)

Description 小Y最近在一家金券交易所工作.该金券交易所只发行交易两种金券:A纪念券(以下简称A券)和 B纪念券(以下 简称B券).每个持有金券的顾客都有一个自己的帐户.金券的数目可以是一个实数.每天随着市场的起伏波动, 两种金券都有自己当时的价值,即每一单位金券当天可以兑换的人民币数目.我们记录第 K 天中 A券 和 B券 的 价值分别为 AK 和 BK(元/单位金券).为了方便顾客,金券交易所提供了一种非常方便的交易方式:比例交易法 .比例交易法分为两个方面:(a)卖出金券:顾客提

【BZOJ3963】[WF2011]MachineWorks cdq分治+斜率优化

[BZOJ3963][WF2011]MachineWorks Description 你是任意性复杂机器公司(Arbitrarily Complex Machines, ACM)的经理,公司使用更加先进的机械设备生产先进的机器.原来的那一台生产机器已经坏了,所以你要去为公司买一台新的生产机器.你的任务是在转型期内尽可能得到更大的收益.在这段时间内,你要买卖机器,并且当机器被ACM公司拥有的时候,操控这些机器以获取利润.因为空间的限制,ACM公司在任何时候都只能最多拥有一台机器. 在转型期内,有若

HDU 3842 Machine Works cdq分治 斜率优化

本题是利用cdq分治  实现斜率优化的一个题目 斜率优化之前做的几个题都是斜率单调,并且插入点时由于点在某一维单调,所以仅仅操作队首和队尾就能完成优化了 但是本题显然不是 主要参考了两个东西 从<Cash>谈一类分治算法的应用 (Day1)cdq分治相关 这两个直接在百度上搜 ,第一个出来的就是 本题的题意是 一个公司获得了一个厂房n(10^5)天的使用权 和一笔启动资金C(10^9),准备在n天里租借机器生产来获得收益 可以租借的机器有M(10^5)个,每个机器有四个值,D,P,R,G (D

【BZOJ-3672】购票 树分治 + 斜率优化DP

3672: [Noi2014]购票 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1177  Solved: 562[Submit][Status][Discuss] Description 今年夏天,NOI在SZ市迎来了她30周岁的生日.来自全国 n 个城市的OIer们都会从各地出发,到SZ市参加这次盛会. 全国的城市构成了一棵以SZ市为根的有根树,每个城市与它的父亲用道路连接.为了方便起见,我们将全国的 n 个城市用 1 到 n 的整数编号.

bzoj [NOI2007]货币兑换Cash (cdq分治+斜率优化 )

1492: [NOI2007]货币兑换Cash Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 2454  Solved: 1078 [Submit][Status][Discuss] Description Input 第一行两个正整数N.S,分别表示小Y 能预知的天数以及初始时拥有的钱数. 接下来N 行,第K 行三个实数AK.BK.RateK,意义如题目中所述 Output 只有一个实数MaxProfit,表示第N 天的操作结束时能够获得的最大的