P1415 拆分数列

https://www.luogu.org/problemnew/show/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[f2[j+1]][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;
}

猜你喜欢

转载自www.cnblogs.com/LLTYYC/p/9506678.html