Luogu 1415-拆分数列-动态规划
Solution
首先要找到使得最后一个数最小, 只需定义一个数组$pre[i]$ 从区间$[pre[i], i]$表示的数, 是最小的能使前面的数递增的方案。
$[ pre[n], n]$即为最小的最后一个数。
接着我们依据这找出的最后一个数, 向前dp, 找出使得每个数都最大的方案。
前导0是非常坑的
我觉得我也不怎么懂这道dp, 看得有点懵TAT
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define rd read() 5 #define rep(i,a,b) for(int i = (a); i <= (b); ++i) 6 #define per(i,a,b) for(int i = (a); i >= (b); --i) 7 using namespace std; 8 9 const int N = 505; 10 11 int pre[N], nxt[N], a[N], n; 12 int ans[N]; 13 14 char s[N]; 15 16 bool cmp(int l1, int r1, int l2, int r2) { 17 while(a[l1] == 0 && l1 <= r1) l1++; 18 while(a[l2] == 0 && l2 <= r2) l2++; 19 if(r1 < l1 || r2 < l2) return 0; 20 if(r1 - l1 < r2 - l2) return 1; 21 else if(r1 - l1 > r2 - l2) return 0; 22 for(int i = 0; i <= r2 - l2; ++i) 23 if(a[l1 + i] > a[l2 + i]) return 0; 24 else if(a[l1 + i] < a[l2 + i]) return 1; 25 return 0; 26 } 27 28 int main() 29 { 30 scanf("%s", s + 1); 31 n = strlen(s + 1); 32 for(int i = 1; i <= n; ++i) a[i] = s[i] - '0'; 33 for(int i = 1; i <= n; ++i) pre[i] = 1; 34 for(int i = 2; i <= n; ++i) 35 for(int j = i; j >= 1; --j) 36 if(cmp(pre[j - 1], j - 1, j, i)) { 37 pre[i] = j; break; 38 } 39 nxt[pre[n]] = n; 40 for(int i = pre[n]; i <= n; ++i) nxt[i] = n; 41 int pos0 = pre[n]; 42 while(a[pos0 - 1] == 0) pos0--, nxt[pos0] = n; 43 for(int i = pre[n] - 1; i; --i) 44 for(int j = pre[n] - 1; j >= i; --j) 45 if(cmp(i, j, j + 1, nxt[j + 1])) { 46 nxt[i] = j; break; 47 } 48 for(int l = 1, i = nxt[1]; l <= n; i = nxt[l]) { 49 for(int j = l; j <= i; j++) printf("%d",a[j]); 50 l = i + 1; 51 if(l > n) break; 52 printf(","); 53 } 54 putchar('\n'); 55 }