• down


    Description
    给出一个数列,求出这个序列的最长下降子序列的长度及方案数,子序列中的权值完全相同视为同一个序列
    Input
    第一行一个整数n,接下来一行n个整数表示序列的权值

    Output
    一行两个整数分别表示最长的长度及方案数

    Sample Input
    样例输入1:

    12
    68 69 54 64 68 64 70 67 78 62 98 87

    样例输入2:

    3
    3 2 2

    样例输出1:

    4 2

    样例输出2:

    2 1
    HINT
    数据范围:

    对于20%的数据n <= 10
    对于50%的数据n <= 200
    对于100%的数据n<= 5000,权值<= 100000,答案不会超出int64(pascal),long long(c++)范围


    要求出最长下降子序列长度及方案数是非常容易的. 关键在于去重.
    对于去重, 可以从头到尾再DP一次.
    第一次DP得到f[i], 即以i为结尾的子串的个数.
    第二次DP维护cnt[i], 表示以i为结尾的长度为f[i]的不同子串的个数.
    具体维护方法是, j从前往后扫, 至i的位置. 假若有 f[j] == f[i] - 1 且 满足a[j] > a[i], 则将j统计入i的前一位中, 即 cnt[i] += cnt[j]. 对于f[i] == 1的位置, cnt[i]直接赋值为1, 表示有且仅有一种情况, 即为它本身. 至于去重, 假如有 a[j] == a[i] 且 j < i, 则将cnt[j]直接赋值为0, 表示以j为结尾的情况在i中都已经进行累加, 以避免后面重复计算.

    这题当时不会写, 只拿了暴力分20, 真的很不应该.

    #include<stdio.h>
    #include<iostream>
    #include<string.h>
    using namespace std;
    const int maxN = (int)5e5;
    int a[maxN];
    int f[maxN];
    long long cnt[maxN];
    int main()
    {
        #ifndef ONLINE_JUDGE
        freopen("down.in", "r", stdin);
        freopen("down.out", "w", stdout);
        #endif
        int n;
        cin >> n;
        for(int i = 0; i < n; i ++)
            cin >> a[i];
        memset(f, 0, sizeof(f));
        for(int i = 0; i < n; i ++)
        {
            for(int j = 0; j < i; j ++)
                if(a[j] > a[i])
                    f[i] = max(f[j] + 1, f[i]);
            if(! f[i])
                f[i] = 1;
        }
        for(int i = 0; i < n; i ++)
        {
            if(f[i] == 1)
                cnt[i] = 1;
            for(int j = 0; j < i; j ++)
                if(a[j] > a[i] && f[j] == f[i] - 1)
                    cnt[i] += cnt[j];
            for(int j = 0; j < i; j ++)
                if(f[j] == f[i] && a[j] == a[i])
                    cnt[j] = 0;
        }
        long long maxLen = 0, ans = 0;
        for(int i = 0; i < n; i ++)
        {
            if(f[i] > maxLen)
                maxLen = f[i], ans = cnt[i];
            else if (f[i] == maxLen)
                ans += cnt[i];
        }
        cout << maxLen << ' ' << ans << endl;
    }
  • 相关阅读:
    linux查看与设置主机名
    为什么用户主目录下.bash_profile没有自动执行
    sqlplus查看服务名
    linux之cp/scp命令+scp命令详解
    查看磁盘使用量
    yum源
    微软输入法删除
    Android下 ionic view 无法登录
    inline-block在ie6中的经典bug
    Apache端口配置
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6402851.html
Copyright © 2020-2023  润新知