1. 程式人生 > >luogu P1415 拆分數列 序列DP

luogu P1415 拆分數列 序列DP

兩個 似的 二次 bsp else () cst 距離 n)

做起來不太難,但是很難想的一道題。

分兩個步驟,第一個步驟是先求出,最後一個數字是多少。

我們考慮d[i]表示,[1,i]最後一個數字最小情況下,最後一個數字的開始位置。

那轉移方程很顯然,d[i] = j(滿足s[d[j - 1],j - 1]<s[j,i],且j距離i最近,這樣子最小)。

這樣我們就求除了最後一個數字是多少。

第二步,我們類似的從後推一遍。

用f[i]表示,[i,n]第一個數字最大情況下,第一個數字的結束位置。

轉移方程依舊顯然,f[i] = j(滿足s[i,j] < s[j + 1,f[j + 1]]且離i最遠的j,這樣子最大)。

然後我們最後順著f[i]輸出即可。

但是有一些問題,就是我們第一步驟求出的最後一個數字,可能存在前導0。

比如100300這個例子,300作為最後一個數字不應該吞並前導零。

而1234050這個例子,50作為最後一個數字應該吞並前導零。

那這個如何處理呢,我們考慮在進行第二次dp前,讓最後一個數字的所有前導零的f值全部為n。然後我們從非零的位置開始DP。可以理解成,我先讓所有前導零與最後一個數字合並,如果前面的某個數字x發現合並了後面這些前導零更優的時候,我允許他把它合並掉,即f[x]指向某些前導零。有種有需要,則自取的感覺。

 1 #include <cstdio>
 2 #include <algorithm>
 3
#include <cstring> 4 using namespace std; 5 char s[510]; 6 int d[510],f[510]; 7 int len; 8 bool cmp(int x1,int y1,int x2,int y2) 9 {//若[x2,y2] > [x1,y1]則返回true 10 while (s[x1] == 0 && x1 != y1) 11 x1++; 12 while (s[x2] == 0 && x2 != y2) 13 x2++;
14 if (y2 - x2 > y1 - x1) 15 return true; 16 else if (y2 - x2 < y1 - x1) 17 return false; 18 for (int i = x1;i <= y1;i++) 19 if (s[i] < s[x2 + i - x1]) 20 return true; 21 else if (s[i] > s[x2 + i - x1]) 22 return false; 23 return false; 24 } 25 void print(int x,int y) 26 { 27 for (int i = x;i <= y;i++) 28 printf("%d",s[i]); 29 if (y != len) 30 printf(","); 31 } 32 bool check(int x,int y) 33 { 34 for (int i = x;i <= y;i++) 35 if (s[i] != 0) 36 return false; 37 return true; 38 } 39 int main() 40 { 41 scanf("%s",s + 1); 42 len = strlen(s + 1); 43 for (int i = 1;i <= len;i++) 44 s[i] -= 0; 45 //d[i]表示,[1,i]最後一個數字最小情況下,最後一個數字的開始位置。 46 d[1] = 1; 47 for (int i = 2;i <= len;i++) 48 for (int j = i;j >= 1;j--) 49 if (cmp(d[j - 1],j - 1,j,i) == true) 50 { 51 d[i] = j; 52 break; 53 } 54 //f[i]表示,[i,n]第一個數字最大情況下,第一個數字的結束位置。 55 int t=d[len]; 56 do 57 { 58 f[t]=len; 59 t--; 60 }while ((t>=1)&&(s[t]==0)); 61 f[d[len]] = len; 62 for (int i = t;i >= 1;i--) 63 for (int j = d[len] - 1;j >= i;j--) 64 if (cmp(i,j,j + 1,f[j + 1]) == true) 65 { 66 f[i] = j; 67 break; 68 } 69 for (int i = 1;i <= len;i++) 70 { 71 print(i,f[i]); 72 i = f[i]; 73 } 74 return 0; 75 }

luogu P1415 拆分數列 序列DP