cychester

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 }
View Code

 

posted on 2018-09-03 20:37  cychester  阅读(207)  评论(0编辑  收藏  举报

导航