• luogu1415 拆分数列


    题目大意

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

    题解

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int MAX_N = 510;
    int A[MAX_N];
    int F1[MAX_N], F2[MAX_N], AnsF2[MAX_N];
    int N;
    
    void CharToA(char *s)
    {
        N = strlen(s + 1);
        for (int i = 1; i <= N; i++)
            A[i] = s[i] - '0';
    }
    
    bool RangeLt(int l1, int r1, int l2, int r2)
    {
        while (A[l1] == 0 && l1 <= r1)
            l1++;
        while (A[l2] == 0 && l2 <= r2)
            l2++;
        if (r1 - l1 != r2 - l2)
            return r1 - l1 < r2 - l2;
        else
            for (int i = 0; i <= r1 - l1; i++)
                if (A[l1 + i] != A[l2 + i])
                    return A[l1 + i] < A[l2 + i];
        return false;
    }
    
    void DP1()
    {
        for (int i = 1; i <= N; i++)
            F1[i] = 1;
        for (int i = 1; i <= N; i++)
            for (int j = 2; j <= i; j++)
                if (RangeLt(F1[j - 1], j - 1, j, i))
                    F1[i] = j;
    }
    
    void DP2(int ed)
    {
        memset(F2, 0, sizeof(F2));
        F2[ed] = N;
        for (int i = ed - 1; i >= 1; i--)
            for (int j = i; j <= ed - 1; j++)
                if (RangeLt(i, j, j + 1, F2[j + 1]))
                    F2[i] = j;
    }
    
    bool CmpF2()
    {
        int cur = 1;
        while (cur <= N)
        {
            if (F2[cur] != AnsF2[cur])
                return F2[cur] > AnsF2[cur];
            cur = F2[cur] + 1;
        }
        return false;
    }
    
    void Print()
    {
        int cur = 1;
        bool tag = false;
        while (cur <= N)
        {
            if (tag)
                putchar(',');
            tag = true;
            for (int i = cur; i <= AnsF2[cur]; i++)
                putchar('0' + A[i]);
            cur = AnsF2[cur] + 1;
        }
    }
    
    int main()
    {
        char s[MAX_N];
        scanf("%s", s + 1);
        CharToA(s);
        DP1();
        DP2(F1[N]);
        memcpy(AnsF2, F2, sizeof(F2));
        for (int i = F1[N] - 1; A[i] == 0; i--)
        {
            if (!RangeLt(F1[i - 1], i - 1, i, N))
                break;
            DP2(i);
            if (CmpF2())
                memcpy(AnsF2, F2, sizeof(F2));
        }
        Print();
        return 0;
    }
    

      

  • 相关阅读:
    树的最小支配集 最小点覆盖 与 最大独立集 (图论)
    P1993 小K的农场 (差分约束)
    P1168 中位数 (优先队列,巧解)
    STL 优先队列
    P3799 妖梦拼木棒 (组合数学)
    P2389 电脑班的裁员 (动态规划)
    3-Java中基本数据类型的存储方式和相关内存的处理方式(java程序员必读经典)
    1-匿名对象
    2-封装性
    2-递归调用
  • 原文地址:https://www.cnblogs.com/headboy2002/p/9479310.html
Copyright © 2020-2023  润新知