zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    阿里云 oss (二) 生成令牌
    doc转html
    js 实现下载本地文件
    vue 中使用video 使用视频/嵌入视频
    小程序裁剪
    车牌号正则
    小程序单选框 radio
    小程序省市三级联动 及日期选择 (年月日)
    小程序图片选择,小程序图片上传及调用后台接口上传
    element ui省市区三级联动,及获取三级联动的name值
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9506678.html
Copyright © 2011-2022 走看看