[BZOJ1563][NOI2009]诗人小G(DP+四边形不等式优化)
程序员文章站
2022-04-01 19:22:17
...
Address
https://www.lydsy.com/JudgeOnline/problem.php?id=1563
Solution
令 为句子长度的前缀和, 为前 个句子的最小不和谐度。
通过证 (gui) 明 (lv) ,我们得到:
故 满足决策单调性。
用一个栈记录决策表。
栈的每个元素是一个三元组 表示当前 的最优决策为 (三个元素都递增)。
一开始栈中有一个元素 。
考虑求出一个 时如何用 更新部分决策。
(1)对于栈顶 ,如果 ,那么 取决策 比 优,可退栈,然后继续执行(1),直到 或者 上式不满足为止。
(2)否则在 内找到一个点 ,使得 取决策 比 优, 取决策 比 优。这时候将栈顶的 改成 ,将三元组 入栈(当然,如果 就不要入栈)。可以用二分查找找到这样的 。
复杂度 。
注意 会超过 long long 范围,要使用 long double 。
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
#define Rof(i, a, b) for (i = a; i >= b; i--)
using namespace std;
typedef long double ld;
const int N = 1e5 + 5, E = 33;
int n, l, p, top, sum[N];
char s[N][E];
ld f[N];
struct cyx {
int l, r, x;
} stk[N];
ld w(int j, int i) {
ld res = 1, a = abs(sum[i] - sum[j] + i - j - 1 - l);
int b = p;
while (b) {
if (b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res;
}
void work() {
int i, j, k, th = 1;
scanf("%d%d%d", &n, &l, &p);
For (i, 1, n) scanf("%s", s[i] + 1),
sum[i] = sum[i - 1] + strlen(s[i] + 1);
stk[top = 1] = (cyx) {1, n, 0};
For (i, 1, n) {
f[i] = f[stk[th].x] + w(stk[th].x, i);
while (stk[top].l > i && f[i] + w(i, stk[top].l) <
f[stk[top].x] + w(stk[top].x, stk[top].l)) top--;
int L = max(stk[top].l, i + 1), R = stk[top].r;
while (L <= R) {
int mid = L + R >> 1;
if (f[i] + w(i, mid) < f[stk[top].x]
+ w(stk[top].x, mid)) R = mid - 1;
else L = mid + 1;
}
stk[top].r = L - 1;
if (L <= n) stk[++top] = (cyx) {L, n, i};
if (stk[th].r == i) th++;
}
if (f[n] > 1e18) puts("Too hard to arrange");
else printf("%lld\n", (long long) (f[n] + 0.5));
puts("--------------------");
}
int main() {
int T; cin >> T;
while (T--) work();
return 0;
}
上一篇: C# 图片反色处理 图片夜间模式