滿足決策單調性的 DP 的通用做法
阿新 • • 發佈:2020-07-25
在研究
http://uoj.ac/contest/37/problem/285
這題時發現了這個東西:
“滿足決策單調性的 DP 的通用做法”
看一道更簡單的例題:
【NOI2009】詩人小G
大概就是:
\(f[i]=min(f[j]+cost(j+1..i))(j<i)\)
然後滿足決策單調性。
一般的決策單調性的題的那種分治是做不了這個的,因為要自己推自己。
考慮還是從左往右dp,維護一個單調佇列,佇列的每個元素形如\((l,r,x)\)表示\([l,r]\)的最優決策點目前是\(x\)。
對於\(i\),先利用隊頭求出\(f[i]\),再考慮加入它成為新的決策點。
從佇列尾開始退,如果隊尾的\(l\)
最後剩一個區間,二分分界點即可。
時間複雜度是:\(O(n~log~n \times 計算代價時間)\)。
分析下和分治法的不同:分治法在計算代價時,分治法同一層可以一起掃來算(有些東西只能這麼算),而不用預處理或快速計算代價函式。
Code:
#include<bits/stdc++.h> #define fo(i, x, y) for(int i = x, _b = y; i <= _b; i ++) #define ff(i ,x, y) for(int i = x, _b = y; i < _b; i ++) #define fd(i, x, y) for(int i = x, _b = y; i >= _b; i --) #define ll long long #define pp printf #define hh pp("\n") using namespace std; #define db long double int T; const int N = 1e5 + 5; int n, p; db len; char s[N][35]; db a[N], pa[N]; struct nod { int l, r, x; } z[N]; db f[N]; int fr[N]; db calc(int l, int r) { db s = 1, x = abs(pa[r] - pa[l] + r - l - 1 - len); for(int y = p; y; y /= 2, x = x * x) if(y & 1) s = s * x; return s + f[l]; } void work() { scanf("%d %Lf %d", &n, &len, &p); fo(i, 1, n) { scanf("%s", s[i] + 1); a[i] = strlen(s[i] + 1); pa[i] = pa[i - 1] + a[i]; } int st = 1, en = 1; z[1] = (nod) {1, n, 0}; fo(i, 1, n) { while(z[st].r < i) st ++; f[i] = calc(z[st].x, i); fr[i] = z[st].x; if(z[st].r <= i) st ++; else z[st].l = i + 1; while(st <= en && calc(i, z[en].l) < calc(z[en].x, z[en].l)) en --; int as; if(st > en) { as = i + 1; } else { as = z[en].r + 1; } for(int l = z[en].l, r = z[en].r; l <= r; ) { int m = l + r >> 1; if(calc(i, m) < calc(z[en].x, m)) { as = m, r = m - 1; } else l = m + 1; } z[en].r = as - 1; if(as <= n) z[++ en] = (nod) {as, n, i}; } if(f[n] > 1e18) { pp("Too hard to arrange\n"); return; } pp("%.0Lf\n", f[n]); static int d[N][2], d0; d0 = 0; for(int x = n; x; x = fr[x]) d[++ d0][0] = fr[x] + 1, d[d0][1] = x; fd(i, d0, 1) { fo(j, d[i][0], d[i][1]) { fo(k, 1, a[j]) pp("%c", s[j][k]); if(j != d[i][1]) pp(" "); } hh; } } int main() { scanf("%d", &T); fo(ii, 1, T) { work(); pp("--------------------\n"); } }