P1912 [NOI2009] 诗人小G 题解
我们设 \(s_i\) 表示前 \(i\) 个句子的长度之和,这样就有 dp
我们设 \(w(l, r) = |s_r - s_l + r - l - 1 - L|^ P\),如果 \(w\) 满足四边形不等式,则原 dp 具有决策单调性。
设 \(u = (s_i + i) - (s_j + j ) - (1 + L)\), \(v = (s_i + i) - (s_j + j + 1 + a_j) - (1 + L)\)。
那么我们证明 \((j < j + 1 < i < i + 1 )\)
等价于证明
因为 \(a_j > 0\),所以 \(u > v\),如果我们设 \(h(x) =|x|^P - |x+z|^P\),那么如果 \(h(x)\) 单调不增,则原命题成立。
证明如下:
我们对绝对值进行讨论。
- 当 \(x \in [0, \infty)\) 时
\[h(x)=x^P - (x+z)^P \\ h'(x) = Px^{P - 1} - P(x + z)^{P - 1} \\ h'(x) = P[x^{P - 1} - (x+z)^{P - 1}] \\ h'(x) = P[x^{P - 1} - \sum_{i = 0}^{P - 1}\binom{P-1}{i}x^{P - 1 - i}z^i] \\ h'(x) = P[-\sum_{i = 1}^{P - 1}\binom{P-1}{i}x^{P - 1 - i}z^i] \\ \]因为 \(P > 0, x > 0, z > 0\),所以 \(h'(x) \le 0, \Box\)
- 当 \(x \in (-\infty, 0)\) 时
注意到此时 \(P\) 的取值会影响到 \(x^P\) 的正负(实际上是 \(h'(x)\) 中 \(x^{P - 1}\) 的正负),所以需要对 \(P\) 的奇偶性进行讨论。
- 当 \(x \in (-\infty, 0)\) ,\(P\) 为偶数时
\[h(x)=x^P - (x+z)^P \\ h'(x) = Px^{P - 1} - P(x + z)^{P - 1} \\ h'(x) = P[x^{P - 1} - (x+z)^{P - 1}] \\ \]注意到只需证 $x^{P - 1} < (x+z)^{P - 1} $,两边同时取 \(\log_{P-1}\),因为 \(z > 0\),所以显然有 \(x < x + z\)。
- 当 $x \in [-z, 0) $ 时,\(P\) 为奇数时
\[h(x)=-x^P - (x+z)^P \\ h'(x) = -Px^{P - 1} - P(x + z)^{P - 1} \\ \]注意到 \(P-1\) 为偶数,所以 \(x^{P-1} > 0\),所以 \(h'(x) \le 0\)。
- 当 \(x \in [-\infty, -z)\) 时,\(P\) 为偶数时
\[h(x)=-x^P + (x+z)^P \\ h'(x) = -Px^{P - 1} + P(x + z)^{P - 1} \\ h'(x) = -P(x^{P - 1}-(x+z)^{P - 1}) \]注意到只需证明 \(x^{P - 1} < (x+z)^{P - 1}\),显然成立,理由同上,所以 \(h'(x) \le 0\)。
综上所述,\(h(x)\) 单调不增。
单调队列维护即可。
\(10^{18}\) 是一个卡的很死的上界,所以最好在过程中用 long double
舍弃精度判断是否大于 \(10^{18}\)。
// 如果命运对你缄默, 那就活给他看。
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast", "inline", "-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define int LL
const int maxn = 1e5 + 10;
char s[maxn][40];
int p[maxn], T, n, L, P, sl[maxn];
long double f[maxn];
long double fp(long double a, int b) {
long double res = 1;
for(; b; b >>= 1, a = a * a)
if(b & 1) res = res * a;
return res;
}
inline long double g(int u, int p) {
return f[p] + fp(abs(sl[u] - sl[p] - L - 1), P);
}
inline void clear() {
memset(p, 0, sizeof p);
memset(f, 0, sizeof f);
}
struct state {
int p, l, r;
} q[maxn];
inline void solve() {
cin >> n >> L >> P;
for(int i = 1; i <= n; ++ i) {
cin >> s[i] + 1;
sl[i] = sl[i - 1] + strlen(s[i] + 1) + 1;
}
int hh = 0, tt = -1;
q[++ tt] = {0, 1, n};
for(int i = 1; i <= n; ++ i) {
while(hh <= tt && q[hh].r < i) hh ++ ;
f[i] = g(i, q[hh].p), p[i] = q[hh].p;
while(hh <= tt && g(q[tt].l, i) <= g(q[tt].l, q[tt].p)) tt -- ;
int l = q[tt].l, r = n + 1;
while(l < r) {
int mid = l + r >> 1;
if(g(mid, i) <= g(mid, q[tt].p)) r = mid;
else l = mid + 1;
}
if(l > n) continue ;
q[tt].r = l - 1;
q[++ tt] = {i, l, n};
}
if(f[n] > 1e18) cout << "Too hard to arrange\n";
else {
cout << fixed << setprecision(0) << f[n] << '\n';
stack <pair<int, int>> st;
for(int x = n; x; x = p[x]) st.emplace(p[x] + 1, x);
while(st.size()) {
auto [l, r] = st.top();
for(int i = l; i < r; ++ i) cout << (s[i] + 1) << ' ';
cout << (s[r] + 1) << '\n';
st.pop();
}
}
cout << "--------------------\n";
}
signed main() {
ios :: sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> T;
while(T -- ) clear(), solve();
return 0;
}