• luoguP1415 拆分数列 [dp]


    题目描述

    给出一列数字,需要你添加任意多个逗号将其拆成若干个严格递增的数。如果有多组解,则输出使得最后一个数最小的同时,字典序最大的解(即先要满足最后一个数最小;如果有多组解,则使得第一个数尽量大;如果仍有多组解,则使得第二个数尽量大,依次类推……)。

    输入输出格式

    输入格式:

    共一行,为初始的数字。

    输出格式:

    共一行,为拆分之后的数列。每个数之间用逗号分隔。行尾无逗号。

    输入输出样例

    输入样例#1:
    [1]
    3456
    [2]
    3546
    [3]
    3526
    [4]
    0001
    [5]
    100000101
    
    输出样例#1:
    [1]
    3,4,5,6
    [2]
    35,46
    [3]
    3,5,26
    [4]
    0001
    [5]
    100,000101
    

    说明

    【题目来源】

    lzn改编

    【数据范围】

    对于10%的数据,输入长度<=5

    对于30%的数据,输入长度<=15

    对于50%的数据,输入长度<=50

    对于100%的数据,输入长度<=500


    《拆分数列》解题报告

    By lzn 动态规划常规题。

    第一步先求出最后的那个数最小为多少。(为了叙述方便,记T(i,j)表示从原数列下标i取到j的数字组成的数。)只需正向dp一次,dp1[i]表示前i个数字分成任意多个递增数且最后的数最小时,最后的数为T(dp1[i],i)。则dp1[i]=max(j),(T(dp1[j-1],j-1)<T(j,i))。

    第二步要求最后一个数确定的情况下,前面的数字按字典序尽量大的解。类似上面的方法反向动归一次即可。

    算法复杂度o(l^3)。由于数据大部分为随机,实际运行效率接近l^2。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<string>
     5 using namespace std;
     6 
     7 const int maxn=505;
     8 
     9 string str;
    10 int a[maxn],n,dP[maxn],Dp[maxn];
    11 
    12 bool cmp(int l1,int r1,int l2,int r2){
    13     while(l1<=r1&&a[l1]==0)  l1++;
    14     while(l2<=r2&&a[l2]==0)  l2++;
    15     int le1=r1-l1+1,le2=r2-l2+1;
    16     if(le1==0||le2==0)  return 0;
    17     if(le1!=le2)  return le1<le2;
    18     for(int i=0;i<le1;i++)
    19         if(a[l1+i]!=a[l2+i])  return a[l1+i]<a[l2+i];
    20     return 0;
    21 }
    22 
    23 //dP[i]=max(j),(T(dP[j-1],j-1)<T(j,i))
    24 void DP1(){
    25     for(int i=1;i<=n;i++){
    26         dP[i]=1;
    27         for(int j=i;j;j--)
    28             if(cmp(dP[j-1],j-1,j,i)){
    29                 dP[i]=j;
    30                 break;
    31             }
    32 //        printf("dP[%d] = %d
    ",i,dP[i]);
    33     }
    34 }
    35 
    36 //Dp[i]=max(j)   (T(i,j)<T(j+1,f[j+1]))
    37 void DP2(){
    38     Dp[dP[n]]=n;
    39     for(int i=dP[n];a[i-1]==0;i--)  Dp[i-1]=n;
    40     
    41     for(int i=dP[n]-1;i;i--){
    42         for(int j=dP[n]-1;j>=i;j--)
    43             if(cmp(i,j,j+1,Dp[j+1])){
    44                 Dp[i]=j;
    45                 break;
    46             }
    47 //        printf("Dp[%d] = %d
    ",i,Dp[i]);
    48     }
    49 }
    50 
    51 void print(int l,int r){
    52     for(int i=l;i<=r;i++)
    53         putchar(a[i]+'0');
    54 }
    55 
    56 void print(){
    57     print(1,Dp[1]);
    58     int pos=Dp[1]+1;
    59     while(pos<=n){
    60         putchar(',');
    61         print(pos,Dp[pos]);
    62         pos=Dp[pos]+1;
    63     }
    64 }
    65 
    66 int main(){
    67     cin>>str;  n=str.length();
    68     for(int i=0;i<n;i++)  a[i+1]=str[i]-'0';
    69     DP1();  DP2();
    70     print();
    71     return 0;
    72 }
  • 相关阅读:
    Linux调整时区和同步时间
    wget命令
    apt-get损坏修复
    apt-get卸载命令
    apt-get命令
    ps命令
    卸载Ambari
    YARN Registry DNS启动提示“53端口被占用”错误的解决方法
    反转链表,时间复杂度O(n),空间复杂度O(1)
    简易版之最短距离
  • 原文地址:https://www.cnblogs.com/ZYBGMZL/p/7296101.html
Copyright © 2020-2023  润新知