zoukankan      html  css  js  c++  java
  • [序列dp]Luogu P1415 拆分数列

    题目描述

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

    输入输出格式

    输入格式:

    共一行,为初始的数字。

    输出格式:

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

    输入输出样例

    [1]
    3456
    [2]
    3546
    [3]
    3526
    [4]
    0001
    [5]
    100000101
    [1]
    3,4,5,6
    [2]
    35,46
    [3]
    3,5,26
    [4]
    0001
    [5]
    100,000101

    【数据范围】

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

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

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

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

    题解

    • 首先,我们可以dp求出为以i结尾的最小结尾数的起始坐标d[i]
    • 求这个dp时,要枚举起始坐标j
    • 那何为满足条件?
    • 也就是结尾数要大于[d[j-1],j-1]
    • 那么最小的话,就是找到一个就直接break,因为这个数是倒过来找的
    • 然后我们还要跑一个dp,从i开始的序列的第一个数的最后的坐标f[i]
    • 题目上说,要满足最后一个数最小,那么我们在上一个dp里求出来的最后一个数,就是答案的最后一个数
    • 求这个的话,从后往前找
    • 也向上面一样,要满足题目的要求
    • 最后,pos沿着f数组找就可以找到全部数

    代码

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 using namespace std;
     5 int d[505],f[505],n,a[505];
     6 char s[505];
     7 bool pd(int l1,int r1,int l2,int r2)
     8 {
     9     while (l1<=r1&&a[l1]==0) l1++;
    10     while (l2<=r2&&a[l2]==0) l2++;
    11     if (r1-l1+1==0||r2-l2+1==0) return false;
    12     if (r1-l1+1<r2-l2+1) return true;
    13     if (r1-l1+1>r2-l2+1) return false;
    14     int len=r1-l1+1;
    15     for (int i=0;i<len;i++)
    16     {
    17         if (a[l1+i]<a[l2+i]) return true;
    18         if (a[l1+i]>a[l2+i]) return false;
    19     }
    20     return false;
    21 }
    22 void dp1()
    23 {
    24     for (int i=1;i<=n;i++)
    25     {
    26         d[i]=1;
    27         for (int j=i;j>=1;j--)
    28             if (pd(d[j-1],j-1,j,i))    
    29             {
    30                 d[i]=j;
    31                 break;
    32             }
    33     }
    34 }
    35 void dp2()
    36 {
    37     f[d[n]]=n;
    38     int x=d[n];
    39     while (a[x-1]==0) f[x-1]=n,x--;
    40     for (int i=d[n]-1;i>=1;i--)
    41         for (int j=d[n]-1;j>=i;j--)
    42             if (pd(i,j,j+1,f[j+1]))
    43             {
    44                 f[i]=j;
    45                 break;
    46             }
    47 }
    48 int main()
    49 {
    50     scanf("%s",s+1);
    51     n=strlen(s+1);
    52     for (int i=1;i<=n;i++) a[i]=s[i]-'0';
    53     dp1(); dp2();
    54     int pos=1;
    55     while (pos<=n)
    56     {
    57         if (pos!=1) putchar(',');
    58         for (int i=pos;i<=f[pos];i++) printf("%d",a[i]);
    59         pos=f[pos]+1;
    60     }
    61     return 0;
    62 }
  • 相关阅读:
    vue组件重新加载的方法
    事件触发方法获取当前值的写法 (含方法要传2个参数的写法)
    mac 解压 rar压缩文件
    表格
    小米8安装charles证书方法
    视频结构化技术栈全解析
    多目标跟踪全解析,全网最全
    SpringBoot
    技术方案设计的方法
    Java的强引用、软引用、弱引用、虚引用
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8529158.html
Copyright © 2011-2022 走看看