P1415 拆分数列

传送门

DP
数列长度过大无法枚举,考虑DP
f1[i]储存以第i个字符为结尾时,的最后一个数最小时,这个数的开头的位置
(很难想有木有)
OK,状态有了,方程想一想就出来了:
设$num[i][j]$为数列中从i到j的数连起来后的值,$len$为数列长度

如果$num[ j ][ i ]>num[ f1[ j -1 ] ][ j-1 ]$( $j$$i$到1 ,$1<=i<=len$)则$f1[ i ]$等于$j$,并且直接退出当前循环
因为$j$从后往前枚举,所以一旦找到符合的j就是$num[ f1[ i ] ][ i ]$的最小值
至于$num$的判断只要打个暴力循环就好了..数据太小..
然后是输出字典序最小的答案(划重点)
仍然是DP..
设$f2[i]$存储以第i个字符为开头时,的最后一个数最小时,这个数的结尾的位置(貌似只是倒过来了..)
同样如果$num[i][j]<num[j+1][f2[j+1]]$( $j$从$n$到$i$,$i$从$n$到$1$)则$f2[i]$等于$j$,并且直接退出当前循环.
还有$f2[f[len]]$初始为$len$
有一点要注意最后一个数可以有前导0..
"如果第一次dp计算出最小末尾为50,但输入是……00050。

这样上面的转移方程不会将000和50分成一组,因为I≤j≤f[n] 。

这样000所在状态就和状态定义不符,它没表示出最大末尾。"

                      __by Rapiz
所以要先把最后一个数的前导0单独处理
听同机房的dalao说好像数据可以扩10倍,判断的话就要用神奇的后缀数组什么的..我也不清楚唉

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
char s[507];
int n,f1[507],f2[507];
inline bool pd(int la,int ra,int lb,int rb)//暴力的判断函数
{
    while(s[la]==0&&la<ra) la++;
    while(s[lb]==0&&lb<rb) lb++;
    //cout<<la<<" "<<ra<<" "<<lb<<" "<<rb<<endl;
    if(ra-la!=rb-lb)
    {
        if(ra-la>rb-lb) return 1;
        else return 0;
    }
    int len=ra-la;
    //cout<<len<<endl;
    //printf("%d %d",s[la+0],s[lb+0]);
    //cout<<endl;
    for(int i=0;i<=len;i++)
        if(s[la+i]!=s[lb+i])
            return s[la+i]>s[lb+i];
    return 0;
}
int main()
{
    scanf("%s",s+1);
    for(int i=1;s[i];i++,n++) s[i]-='0';
    //DP开始
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j>0;j--)
            if(pd(j,i,f1[j-1],j-1))
            {
                f1[i]=j;
                break;
            }
    }
    int tot=1;
    //cout<<f1[n];
    for(int i=f1[n]-1;i&&s[i]==0;i--) f2[i]=n,tot++;
    f2[f1[n]]=n;
    for(int i=f1[n]-tot;i>0;i--)
    {
        f2[i]=i;
        for(int j=f1[n]-1;j>=i;j--)
            if(pd(j+1,f2[j+1],i,j))
            {
                f2[i]=max(f2[i],j);
                break;
            }
    }
    int pos=f2[1];
    for(int i=1;i<=n;i++)
    {
        if(i==pos&&i!=n)
        {
            printf("%d,",s[i]);
            pos=f2[i+1];
            continue;
        }
        printf("%d",s[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/LLTYYC/p/9506678.html