Luogu 1415-拆分数列-动态规划

时间:2023-03-10 03:00:16
Luogu 1415-拆分数列-动态规划

Solution

首先要找到使得最后一个数最小, 只需定义一个数组$pre[i]$ 从区间$[pre[i], i]$表示的数, 是最小的能使前面的数递增的方案。

$[ pre[n], n]$即为最小的最后一个数。

接着我们依据这找出的最后一个数, 向前dp, 找出使得每个数都最大的方案。

前导0是非常坑的

我觉得我也不怎么懂这道dp, 看得有点懵TAT

Code

 #include<cstdio>
#include<cstring>
#include<algorithm>
#define rd read()
#define rep(i,a,b) for(int i = (a); i <= (b); ++i)
#define per(i,a,b) for(int i = (a); i >= (b); --i)
using namespace std; const int N = ; int pre[N], nxt[N], a[N], n;
int ans[N]; char s[N]; bool cmp(int l1, int r1, int l2, int r2) {
while(a[l1] == && l1 <= r1) l1++;
while(a[l2] == && l2 <= r2) l2++;
if(r1 < l1 || r2 < l2) return ;
if(r1 - l1 < r2 - l2) return ;
else if(r1 - l1 > r2 - l2) return ;
for(int i = ; i <= r2 - l2; ++i)
if(a[l1 + i] > a[l2 + i]) return ;
else if(a[l1 + i] < a[l2 + i]) return ;
return ;
} int main()
{
scanf("%s", s + );
n = strlen(s + );
for(int i = ; i <= n; ++i) a[i] = s[i] - '';
for(int i = ; i <= n; ++i) pre[i] = ;
for(int i = ; i <= n; ++i)
for(int j = i; j >= ; --j)
if(cmp(pre[j - ], j - , j, i)) {
pre[i] = j; break;
}
nxt[pre[n]] = n;
for(int i = pre[n]; i <= n; ++i) nxt[i] = n;
int pos0 = pre[n];
while(a[pos0 - ] == ) pos0--, nxt[pos0] = n;
for(int i = pre[n] - ; i; --i)
for(int j = pre[n] - ; j >= i; --j)
if(cmp(i, j, j + , nxt[j + ])) {
nxt[i] = j; break;
}
for(int l = , i = nxt[]; l <= n; i = nxt[l]) {
for(int j = l; j <= i; j++) printf("%d",a[j]);
l = i + ;
if(l > n) break;
printf(",");
}
putchar('\n');
}