Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

P1912 [NOI2009] 诗人小G

P1912 [NOI2009] 诗人小G

可以发现决策点单调增加证明略。

1D1D 的模板。用队列维护。先将 $0, 1, n$ 放入队列表示 $[1, n]$ 可以从 $0$ 转移。对于每个 $i$ ,首先将范围不到 $i$ 的弹出,得到转移点并转移。如果在 $l$ 点转移不如 $i$ ,那么后面这一段一定不如 $i$ ,弹出。此时找到了一个在左侧从原来的转移点更优,但在右侧从 $i$ 转移更优的三元组。从中二分处分界线,拆分即可。全程维护一个 $p$ 表示当前删除的区间 $[p, n]$ ,最后补上三元组 $i, p, n$ 。

另外一个坑:千万不要使用 cmath 库中的 pow ,其实现比 $O(n)$ 还慢。

__int128 会溢出,需要使用 long double

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long double LD;
const LD inf = 1e18;
const int N = 1e5 + 10, S = 40;
char str[N][S];
int n, pre[N];
LD L, P, s[N], f[N];
struct Node
{
int p, l, r;
} q[N];
int hd, tl;
void print(int l, int r)
{
if (l)
print(pre[l], l);
for (int i = l + 1; i < r; i++)
printf("%s ", str[i] + 1);
printf("%s\n", str[r] + 1);
}
LD binpow(LD b, int k)
{
LD res = 1;
while (k)
{
if (k & 1)
res = res * b;
b = b * b;
k >>= 1;
}
return res;
}
LD cal(int i, int j)
{
return f[j] + binpow(abs(s[i] - s[j] + i - j - 1 - L), P);
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%Lf%Lf", &n, &L, &P);
for (int i = 1; i <= n; i++)
{
scanf("%s", str[i] + 1);
s[i] = s[i - 1] + strlen(str[i] + 1);
}
hd = 1, tl = 0;
q[++tl] = (Node){0, 1, n};
for (int i = 1; i <= n; i++)
{
while (hd <= tl && q[hd].r < i)
hd++;
pre[i] = q[hd].p;
f[i] = cal(i, q[hd].p);
int p = n + 1;
while (hd <= tl && cal(q[tl].l, i) <= cal(q[tl].l, q[tl].p))
p = q[tl--].l;
if (hd <= tl && cal(q[tl].r, i) <= cal(q[tl].r, q[tl].p))
{
int l = q[tl].l, r = q[tl].r;
while (l <= r)
{
int mid = l + r >> 1;
cal(mid, i) <= cal(mid, q[tl].p) ? (p = mid, r = mid - 1) : l = mid + 1;
}
q[tl].r = p - 1;
}
if (p <= n)
q[++tl] = {i, p, n};
}
if (f[n] > inf)
puts("Too hard to arrange");
else
{
printf("%.0Lf\n", f[n]);
print(pre[n], n);
}
puts("--------------------");
}
return 0;
}