算法学习——决策单调性优化DP
update in 2019.1.21 優(yōu)化了一下文中年代久遠(yuǎn)的代碼 的格式……
?
什么是決策單調(diào)性?
在滿足決策單調(diào)性的情況下,通常決策點(diǎn)會(huì)形如1111112222224444445555588888.....
即不可能會(huì)出現(xiàn)后面點(diǎn)的決策點(diǎn)小于前面點(diǎn)的決策點(diǎn)這種情況。
那么這個(gè)性質(zhì)應(yīng)該如何使用呢?
1,二分。
考慮到?jīng)Q策點(diǎn)單調(diào)遞增,因此我們考慮用單調(diào)隊(duì)列存下當(dāng)前的決策選取情況。
單調(diào)隊(duì)列中存的量會(huì)帶3個(gè)信息:這是哪個(gè)決策點(diǎn),這個(gè)決策點(diǎn)會(huì)給哪個(gè)區(qū)間的點(diǎn)產(chǎn)生貢獻(xiàn)(這是一個(gè)區(qū)間,所以算2個(gè)信息)
相當(dāng)于隊(duì)列中存了很多個(gè)區(qū)間,假設(shè)當(dāng)前的決策點(diǎn)是這樣的:1111112222222333333,
現(xiàn)在插入4這個(gè)決策,那么我們就是要找到最靠左的合法位置將決策序列變?yōu)轭愃七@樣的序列:111111222222444444444,
因?yàn)闆Q策單調(diào),所以要覆蓋肯定是一整段一整段的覆蓋,因此我們先判斷4是否可以覆蓋完3這個(gè)區(qū)間,只需要看3的左端點(diǎn)是否可以被替換即可。
我們重復(fù)覆蓋整個(gè)區(qū)間這個(gè)操作,直到有個(gè)區(qū)間無法被完整覆蓋,或者已經(jīng)到了不合法的位置(因?yàn)榈趚個(gè)點(diǎn)只能給區(qū)間[x + 1, n]內(nèi)的點(diǎn)產(chǎn)生貢獻(xiàn))。
如果這個(gè)區(qū)間無法被完整覆蓋,那么我們就在這個(gè)區(qū)間內(nèi)二分找到最靠左的點(diǎn)使得4可以替換掉這個(gè)區(qū)間內(nèi)的數(shù),然后修改管理這個(gè)區(qū)間的數(shù)的區(qū)間,把被覆蓋的區(qū)間讓給4.
每次操作前彈掉已經(jīng)沒有用的決策點(diǎn),于是可以實(shí)現(xiàn)O(1)轉(zhuǎn)移。(例如當(dāng)前隊(duì)首的決策點(diǎn)可以更新[3, x-1]這個(gè)區(qū)間,但我們已經(jīng)枚舉到x了,所以這個(gè)決策點(diǎn)顯然就沒有什么用了)
以下是某個(gè)年代久遠(yuǎn)的一道決策單調(diào)性優(yōu)化的代碼。
?
1 /*[NOI2009]詩(shī)人小G by ww3113306*/ 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define R register int 5 #define AC 100100 6 #define LL long long 7 #define LD long double 8 #define ac 101000 9 #define inf 1000000000000000000LL 10 int t, L, p, n; 11 int Next[AC], s[AC], last[AC], l[AC], r[AC];//對(duì)應(yīng)決策的管理區(qū)間,Next對(duì)last進(jìn)行相反操作,以便輸出 12 int q[AC], head, tail;//存下當(dāng)前是哪個(gè)決策 13 LD f[AC]; 14 LL sum[AC]; 15 char ss[ac][45]; 16 17 inline LD qpow(LD x)//error!!!x也要用LD!!! 18 { 19 LD ans = 1;int have = p; 20 while(have) 21 { 22 if(have & 1) ans *= x; 23 x *= x, have >>= 1; 24 } 25 return ans; 26 } 27 28 inline LD count(int x, int j){return f[j] + qpow(abs(sum[x] - sum[j] - L - 1));}//j --- > x 29 30 inline void pre() 31 { 32 scanf("%d%d%d", &n, &L, &p); 33 for(R i = 1; i <= n; i ++) 34 { 35 scanf("%s", ss[i] + 1); 36 s[i] = strlen(ss[i] + 1) + 1;//加上后面的空格 37 sum[i] = sum[i-1] + s[i];//求出前綴和 38 } 39 } 40 41 void half(int x)//二分查找 42 { 43 int now = q[tail], ll = max(l[now], x + 1), rr = n, mid;//因?yàn)榭赡芸梢愿采w多個(gè)區(qū)間 44 while(ll < rr) 45 { 46 mid = (ll + rr) >> 1; 47 if(count(mid, x) < count(mid, now)) rr = mid;//如果更優(yōu)就往左縮短 48 else ll = mid + 1;//不然就向右尋找 49 } 50 r[q[tail]] = ll - 1; 51 q[++tail] = x, l[x] = ll, r[x] = n; 52 } 53 54 inline void getans() 55 { 56 head = 1, tail = 1, q[1] = 0, l[0] = 1, r[0] = n; 57 for(R i = 1; i <= n; i ++) 58 { 59 while(r[q[head]] < i) ++head;//如果當(dāng)前隊(duì)首已經(jīng)取不到了 60 int now = q[head]; 61 f[i] = count(i, now);//error ??? 用函數(shù)的話會(huì)爆了會(huì)自動(dòng)轉(zhuǎn)換為inf? 62 last[i] = now; 63 if(count(n, q[tail]) < count(n, i)) continue;//如果最后一個(gè)都不夠優(yōu),那就不二分了 64 while(count(l[q[tail]], q[tail]) > count(l[q[tail]], i)) --tail;//如果當(dāng)前可以覆蓋前面的整個(gè)區(qū)間 65 half(i);//注意上面的while要在調(diào)用half之前修改,這樣取到的now才是正確的 66 } 67 } 68 69 inline void write() 70 { 71 if(f[n] > inf) puts("Too hard to arrange"); 72 else 73 { 74 printf("%lld\n", (LL)(f[n] + 0.5));//注意精度誤差 75 for(R i = n; i; i = last[i]) Next[last[i]] = i; 76 int now = 0; 77 for(R i = 1; i <= n; i ++) 78 { 79 now = Next[now];//now先跳了吧 80 int be = now;//先只到這行結(jié)尾,因?yàn)閒or還要加的 81 for(R j = i; j < be; j ++) printf("%s ", ss[j] + 1); 82 printf("%s\n", ss[be] + 1), i = be;//最后再賦i,因?yàn)閒or中還要用到當(dāng)前i 83 } 84 } 85 puts("--------------------"); 86 } 87 88 int main() 89 { 90 scanf("%d", &t); 91 while(t--) pre(), getans(), write(); 92 return 0; 93 } View Code?
2,分治
假設(shè)我們當(dāng)前的被決策區(qū)間是[l, r], 決策點(diǎn)區(qū)間是[ll, rr],那么我們?nèi)”粵Q策區(qū)間的中點(diǎn)mid = (l + r) >> 1,然后在[ll, rr]中暴力尋找mid的最優(yōu)決策點(diǎn)k,于是根據(jù)決策單調(diào)性,我們有:
被決策區(qū)間[l, mid - 1]對(duì)應(yīng)的決策點(diǎn)區(qū)間是[ll, k].同理,被決策區(qū)間[mid + 1, r]對(duì)應(yīng)的決策點(diǎn)區(qū)間是[k, rr],于是我們就將這個(gè)區(qū)間劃分為了2半,不斷向下遞歸減小決策點(diǎn)范圍即可用正確的復(fù)雜度求出所有的轉(zhuǎn)移。
?
轉(zhuǎn)載于:https://www.cnblogs.com/ww3113306/p/9889295.html
總結(jié)
以上是生活随笔為你收集整理的算法学习——决策单调性优化DP的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 广发银行个人网上银行怎么登录?网银登录步
- 下一篇: 微众银行可以绑定信用卡吗?怎么解绑?