[bzoj3156]防御准备
试题描述
背景
在美丽富饶的Katharon国中生活着一群快乐的小木偶。他们衣食无忧,自给自足。然而在某一天,来自外形的X过要对Katharon国,发起攻击,国家安危迫在眉睫,下面请你来做战前的防御准备工作。
描述
我们定义战线为一条长度为n的序列,在这条战线上共设有n个检查点,从左到右依次标号为1到n。一个战线为合法战线当且仅当任意一个检查点可以通过安全检查。对于第i个检查点可以通过安全检查的方式有两种,第一种是放置一个守卫塔,这将花费ai的费用。第二种方式是放置一个木偶,放置木偶的话费等于这个检查点右侧第一个守卫塔到它的距离。举例来说,若检查点第i个位置放置一个木偶,检查点右侧第一个守卫塔位置为j(i < j),则在点i放置木偶的花费为j - i.当然,第n个检查点只能放置守卫塔,因为它的右面不可能再存在别的守卫塔了。我们定义战线花费为所有守卫塔的花费加上所有木偶的花费,现在Katharon国的国王hzc君将提供给你每个位置放置守卫塔的费用以及战线的总长度,请你求出最小的战线花费值。
输入
第一行为一个整数N表示战线的总长度。
第二行N个整数,第i个整数表示在位置i放置守卫塔的花费Ai。
输出
共一个整数,表示最小的战线花费值。
输入示例
10 2 3 1 5 4 5 6 3 1 2
输出示例
18
数据范围
1<=N<=10^6,1<=Ai<=10^9
题解
原题试题描述是一张截图。我没事闲的,也为方便你们查题解,手打了一份。。。
不用多说,此题和[bzoj3437]小P的牧场极其相似,但是简单多了,不需要“反着”考虑。
设f(i)表示使前i个检查点合法,并且第i个点放置守卫塔的最小花费。
转移和斜率优化做法留给读者思考。
#include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <stack> #include <vector> #include <queue> #include <cstdlib> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *tail; inline char Getchar() { if(Head == tail) { int l = fread(buffer, 1, BufferSize, stdin); tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); } while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); } return x * f; } #define maxn 1000010 #define LL long long int n, A[maxn], l, r, q[maxn]; LL f[maxn]; double slop(int j, int k) { return (double)((f[j] << 1ll) - (f[k] << 1ll) + (double)j * j + j - (double)k * k - k) / (2.0 * (j - k)); } int main() { n = read(); for(int i = 1; i <= n; i++) A[i] = read(); l = r = 1; q[r] = 0; for(int i = 1; i <= n; i++) { while(l < r && slop(q[l], q[l+1]) < i) l++; f[i] = f[q[l]] + ((LL)(i - q[l]) * (LL)(i - q[l] - 1) >> 1ll) + A[i]; // for(int t = l; t <= r; t++) printf("%d(%lld) ", q[t], f[q[t]]); putchar(‘\n‘); while(l < r && slop(q[r], i) < slop(q[r-1], q[r])) r--; q[++r] = i; } printf("%lld\n", f[n]); return 0; }
代码?点这儿!
时间: 2024-10-27 07:33:47