• ACM学习历程—UESTC 1217 The Battle of Chibi(递推 && 树状数组)(2015CCPC C)


    题目链接:http://acm.uestc.edu.cn/#/problem/show/1217

    题目大意就是求一个序列里面长度为m的递增子序列的个数。

    首先可以列出一个递推式p(len, i) = sum(p(len-1, j)) (a[j] < a[i])

    p(len, i)表示以第i个结尾的长度为len的子序列的个数。

    但是如果按照递增子序列的思想,然后直接弄的话,复杂度是n*m*n的。

    如果需要优化的话,可以优化的地方就是那个求sum的过程。

    p数组映射到树状数组,那么求和的过程就能在logn时间完成。

    这样写完是m*logn,一不小心可能写成nlogn的。。

    不过这样竟然还是T(比赛的时候能过,不知道是评测机性能不一样,还是加数据了)。

    需要加一个剪枝,就是从长度1m枚举时,当某次查询的结果为0时,说明前面的子序列长度都达不到这个长度了,那么更长的显然也达不到了,于是此时直接breakOK了。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #define LL long long
    #define MOD 1000000007
    
    using namespace std;
    
    const int maxN = 1005;
    int n, m;
    struct node
    {
        int v;
        int id;
    }a[maxN];
    
    bool cmp(node x, node y)
    {
        if (x.v != y.v) return x.v < y.v;
        else return x.id > y.id;
    }
    
    LL d[maxN][maxN];
    
    int lowbit(int x)
    {
        return x&(-x);
    }
    
    void add(int len, int id, LL pls)
    {
        while(id <= maxN)//id最大是maxN
        {
            d[len][id] += pls;
            d[len][id] %= MOD;
            id += lowbit(id);
        }
    }
    
    LL sum(int len, int to)
    {
        LL s = 0;
        while(to > 0)
        {
            s = (s+d[len][to])%MOD;
            to -= lowbit(to);
        }
        return s;
    }
    
    void input()
    {
        scanf("%d%d", &n, &m);
        int k;
        for (int i = 0; i < n; ++i)
        {
            scanf("%d", &k);
            a[i].id = i+1;
            a[i].v = k;
        }
        sort(a, a+n, cmp);
        memset(d, 0, sizeof(d));
    }
    
    void work()
    {
        LL k;
        for (int i = 0; i < n; ++i)
        {
            add(1, a[i].id, 1);
            for (int j = 2; j <= m; ++j)
            {
                k = sum(j-1, a[i].id-1);
                if (!k) break;
                add(j, a[i].id, k);
            }
        }
        printf("%lld
    ", sum(m, n));
    }
    
    int main()
    {
        //freopen("test.in", "r", stdin);
        int T;
        scanf("%d", &T);
        for (int times = 1; times <= T; ++times)
        {
            printf("Case #%d: ", times);
            input();
            work();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    linux下进程的实际用户ID(有效组)和有效用户ID(有效组ID)
    ubuntu下软件中心闪退问题解决
    LINUX(UNIX)文件I/O学习
    ubunut下桌面文件路径修改
    ubuntu下设置jdk/jre环境
    Fire net
    JavaScript 自己写一个 replaceAll() 函数
    Canvas 绘制一个像素风电子时钟
    Python3 笔记01:求两数之和
    尝试笔记 01 之 CSS 边角上的标签
  • 原文地址:https://www.cnblogs.com/andyqsmart/p/4997531.html
Copyright © 2020-2023  润新知