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;
    }
  • 相关阅读:
    有点忙啊
    什么是协程
    HDU 1110 Equipment Box (判断一个大矩形里面能不能放小矩形)
    HDU 1155 Bungee Jumping(物理题,动能公式,弹性势能公式,重力势能公式)
    HDU 1210 Eddy's 洗牌问题(找规律,数学)
    HDU1214 圆桌会议(找规律,数学)
    HDU1215 七夕节(模拟 数学)
    HDU 1216 Assistance Required(暴力打表)
    HDU 1220 Cube(数学,找规律)
    HDU 1221 Rectangle and Circle(判断圆和矩形是不是相交)
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9506678.html
Copyright © 2011-2022 走看看