BZOJ 1563 四边形不等式
Description
Input
Output
Sample Input
4 9 3
brysj,
hhrhl.
yqqlm,
gsycl.
4 9 2
brysj,
hhrhl.
yqqlm,
gsycl.
1 1005 6
poet
1 1004 6
poet
Sample Output
--------------------
32
--------------------
Too hard to arrange
--------------------
1000000000000000000
--------------------
【样例说明】
前两组输入数据中每行的实际长度均为6,后两组输入数据每行的实际长度均为4。一个排版方案中每行相邻两个句子之间的空格也算在这行的长度中(可参见样例中第二组数据)。每行末尾没有空格。
HINT
总共10个测试点,数据范围满足:
测试点 T N L P
1 ≤10 ≤18 ≤100 ≤5
2 ≤10 ≤2000 ≤60000 ≤10
3 ≤10 ≤2000 ≤60000 ≤10
4 ≤5 ≤100000 ≤200 ≤10
5 ≤5 ≤100000 ≤200 ≤10
6 ≤5 ≤100000 ≤3000000 2
7 ≤5 ≤100000 ≤3000000 2
8 ≤5 ≤100000 ≤3000000 ≤10
9 ≤5 ≤100000 ≤3000000 ≤10
10 ≤5 ≤100000 ≤3000000 ≤10
所有测试点中均满足句子长度不超过30。
四边形不等式优化dp使用条件:
若dp[i] = Min(dp[j] + val(i, j)), 如果val(i, j)满足(val(i, j) + val(i + 1, j + 1) <= val(i, j + 1) + val(i + 1, j),即val满足四边形不等式,则该dp方程满足决策单调性。
即对每一个dp[i],其转移过来的位置p[i]序列有单调性。
利用决策单调性,将复杂度降低至nlogn。
具体操作:
建一个元素为(x, l, r)(表示l ~ r之间的dp值最优决策都是由位置x处转移)的队列。
(1) 每次更新检查队头的r是否为i - 1,如果是,踢掉;否则更新队头的l值为i;
(2)直接取队头的x值更新dp[i],即dp[i] = dp[x] + val(i, x);
接下来要维护队尾满足决策单调
(3)如果队尾的l, x满足dp[x] + val(l, x) > dp[i] + val(l, i) 踢掉; 不断重复此操作
(4)在队尾的区间内二分得到最小的ans(默认r + 1),使得dp[i] + val(ans, i) < dp[x] + val(ans, x);
(5)更改队尾r为ans - 1;队尾加入(i, ans, n)
1 #include <iostream> 2 #include <fstream> 3 #include <sstream> 4 #include <cstdlib> 5 #include <cstdio> 6 #include <cmath> 7 #include <string> 8 #include <cstring> 9 #include <algorithm> 10 #include <queue> 11 #include <stack> 12 #include <vector> 13 #include <set> 14 #include <map> 15 #include <list> 16 #include <iomanip> 17 #include <cctype> 18 #include <cassert> 19 #include <bitset> 20 #include <ctime> 21 22 using namespace std; 23 24 #define pau system("pause") 25 #define ll long long 26 #define pii pair<int, int> 27 #define pb push_back 28 #define mp make_pair 29 #define mp make_pair 30 #define pli pair<ll, int> 31 32 const double pi = acos(-1.0); 33 const int INF = 0x3f3f3f3f; 34 const int MOD = 1e9 + 7; 35 const double EPS = 1e-9; 36 37 /* 38 #include <ext/pb_ds/assoc_container.hpp> 39 #include <ext/pb_ds/tree_policy.hpp> 40 using namespace __gnu_pbds; 41 #define tree<pli, null_type, greater<pli>, rb_tree_tag, tree_order_statistics_node_update> TREE 42 TREE T; 43 */ 44 45 const int M = 1018; 46 int T, n, l, p, a[100015], sum[100015]; 47 long double dp[100015]; 48 struct gg { 49 int x, l, r; 50 gg () {} 51 gg (int x, int l, int r) : x(x), l(l), r(r) {} 52 } g[100015]; 53 int ql, qr; 54 char s[35]; 55 long double val(int i, int j) { 56 return dp[j] + pow(abs(sum[i] - sum[j] + i - j - 1 - l), p); 57 } 58 int main() { 59 scanf("%d", &T); 60 while (T--) { 61 scanf("%d%d%d", &n, &l, &p); 62 for (int i = 1; i <= n; ++i) { 63 scanf("%s", s); 64 a[i] = strlen(s); 65 sum[i] = sum[i - 1] + a[i]; 66 } 67 g[ql = qr = 1] = gg(0, 1, n); 68 for (int i = 1; i <= n; ++i) { 69 if (g[ql].r == i - 1) ++ql; 70 else g[ql].l = i; 71 int j = g[ql].x; 72 long double x = abs(sum[i] - sum[j] + i - j - 1 - l); 73 dp[i] = dp[j] + pow(x, p); 74 while (ql <= qr) { 75 int tl = g[qr].l, j = g[qr].x; 76 if (val(tl, j) > val(tl, i)) --qr; 77 else break; 78 } 79 int s = g[qr].l, e = g[qr].r, ans = e + 1, mi; 80 j = g[qr].x; 81 while (s <= e) { 82 mi = s + e >> 1; 83 if (val(mi, j) > val(mi, i)) e = (ans = mi) - 1; 84 else s = mi + 1; 85 } 86 g[qr].r = ans - 1; 87 if (ans <= n) g[++qr] = gg(i, ans, n); 88 } 89 if (dp[n] <= 1e18) { 90 printf("%lld\n", (ll)dp[n]); 91 } else { 92 puts("Too hard to arrange"); 93 } 94 puts("--------------------"); 95 } 96 return 0; 97 }