NOIP模拟(10.27)T2 遥远的金字塔

来源:互联网 发布:网络机房升级改造方案 编辑:程序博客网 时间:2024/06/05 01:01

遥远的金字塔

题目背景:

10.27 NOIP模拟T2

分析:斜率优化DP

 

讲道理,NOIP这么考真的好吗,而且我特喵很想知道啊,为毛能够把我的正解卡T啊,我真的是非常不爽啊,喵喵喵喵喵

讲题。

首先,我们可以知道,如果因为这一行是严格小于上一行的,并且我们稍微用脑袋想想就知道,最优的方式一定是,选择连续很多条,然后宽度就是最窄的那一条就好了,那么我们就可以考虑用dp来做了。定义dp[i][c]表示,目前在第i行,已经选择了c个矩形的最优解,那么转移显然就是

dp[i][c] = dp[j][c - 1] + (i - j) * l[i](l[j]表示,j的宽度),那么这样呢,我们就已经有了一个O(n2k)的算法了,显然过不去·····考虑如何优化,我们来推推式子,如果对于两个dp[j][c - 1]dp[k][c - 1]j > k,如果从j转移更优秀的话,满足

dp[j][c - 1] + i * l[i] - j * l[i] > dp[k][c - 1] + i * l[i] - k *l[i]

ð dp[j][c - 1] - dp[k][c - 1] > (j - k)l[i]

ð (dp[j][c - 1] - dp[k][c - 1]) / (j - k) > l[i]

也就是说当满足上面的不等式时,jk作为决策更加优,那么我们定义上面的额S(k, j) = (dp[j][c - 1] - dp[k][c - 1]) / (j - k), 那么如果存在三个决策满足, S(k, j) <S(j, x),那么j一定是没有意义的决策,因为,如果S(k, j) < l[i],那么显然kj优,如果S(k, j) > l[i], 那么S(j, x) > l[i],那么x又一定比j优,所以我们只需要维护一个双端队列,每次加入新决策前,先将倒数两个决策和新的决策比较,将不够优秀的决策扔出去,而每一次需要选择i的决策时,将前面所有S(k, j) > l[i]k弹出,最后留在队首的就是i的决策,这样复杂度就被优化成O(nk)啦,然后这就是标算复杂度了。

Source:

/*created by scarlyw*/#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#include <string>#include <cmath>#include <cctype>#include <queue>#include <vector>#include <ctime>inline char read() {static const int IN_LEN = 1024 * 1024;static char buf[IN_LEN], *s, *t;if (s == t) {t = (s = buf) + fread(buf, 1, IN_LEN, stdin);if (s == t) return -1;}return *s++;}template<class T>inline void R(T &x) {static char c;static bool iosig;for (c = read(), iosig = false; !isdigit(c); c = read()) {if (c == -1) return ;if (c == '-') iosig = true;}for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1) + (c ^ '0');if (iosig) x = -x;}const int OUT_LEN = 1024 * 1024;char obuf[OUT_LEN], *oh = obuf;inline void write_char(char c) {if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;*oh++ = c;}template<class T>inline void W(T x) {static int buf[30], cnt;if (x == 0) write_char('0');else {if (x < 0) write_char('-'), x = -x;for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;while (cnt) write_char(buf[cnt--]);}}inline void flush() {fwrite(obuf, 1, oh - obuf, stdout);}/*template<class T>inline void R(T &x) {static char c;static bool iosig;for (c = getchar(), iosig = false; !isdigit(c); c = getchar()) {if (c == -1) return ;if (c == '-') iosig = true;}for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0');if (iosig) x = -x;}//*/const int MAXN = 20000 + 10;const int MAXK = 100 + 10;int n, k, x, y;long long dp[MAXN], f[MAXN];int l[MAXN];inline void read_in() {R(n), R(k);for (int i = 1; i <= n; ++i) R(x), R(y), l[i] = y - x + 1;}inline double calc(int k, int j) {return (double)(dp[j] - dp[k]) / (double)(j - k);}inline void solve() {std::deque<int> q;for (int c = 1; c <= k; ++c) {q.clear(), q.push_back(0);for (int i = 1; i <= n; ++i) {while (q.size() >= 2 && calc(q[0], q[1]) > l[i]) q.pop_front();f[i] = (long long)(i - q[0]) * (long long)l[i] + dp[q[0]];while (q.size() >= 2 && calc(q[q.size() - 2], q[q.size() - 1]) < calc(q[q.size() - 1], i)) q.pop_back();q.push_back(i);}for (int i = 1; i <= n; ++i) dp[i] = f[i];}long long ans = 0;for (int i = 1; i <= n; ++i) ans = std::max(ans, f[i]);std::cout << ans;}int main() {//freopen("pyramid.in", "r", stdin);//freopen("pyramid.out", "w", stdout);read_in();solve();return 0;}

阅读全文
0 0