• wmq的队伍 BIT优化dp


    http://oj.xjtuacm.com/problem/14/

    wmq的队伍

    发布时间: 2017年4月9日 17:06   最后更新: 2017年4月9日 17:07   时间限制: 2000ms   内存限制: 512M

    交大上课需要打卡,于是在上课前的几分钟打卡机前往往会排起长队。

    平时早睡早起早早打卡的wmq昨晚失眠,今天起晚了,于是他也加入了打卡队伍中。

    这个时候,wmq发现了神奇的现象,打卡队伍可以按人们的身高看成一个队列,左边是队头,右边是队尾。

    对于队列a1...an,wmq想知道其中存在多少的有序k元组l1...lk

    使得1l1<l2<...<lkn,并且有al1>al2>...>alk

    输入有多组数据

    第一行是一个正整数T1T15,代表数据组数

    每组数据第一行是两个正整数nk1n21041kmin(n,100)

    n代表队列的人数,k 的含义见题面

    接下来一行有n个正整数,代表1n的一个排列,表示队伍的身高情况

    对于每组数据,输出一个整数,代表有序k元组的个数

    考虑到数字可能很大,将答案对109+7取模之后输出

     复制
    3
    2 2
    1 2
    2 2
    2 1
    22 3
    1 2 3 4 5 16 6 7 8 9 10 19 11 12 14 15 17 18 21 22 20 13
    0
    1
    8

    这题是一眼看破的题了,设dp[i][k]表示以第i个数字结尾的时候,下降子序列长度为k时的种类数。

    那么dp[i][k] = sigma dp[res][k - 1],a[res] > a[i], 1 <= res <= i - 1

    那么答案就是 sigma dp[i][k],    1 <= i  <= n

    然后发现这样会超时,就马上否认了这个做法。于是做了3小时。

    其中有一种比较有趣的想法是考虑每一个数字贡献,以

    4、3、2、1,k = 3为例子。算出每一个位置的逆序对数,那么对于每一个点,如果它的逆序对 + 1 >= k的,就可以作为贡献

    也就是,比如2的逆序对有2对,那么加上2就形成一个长度为3的下降子序列,这个时候有C(2, 2) = 1种,意思就是不包括2的话,我还要选出k - 1 = 2个数字,形成长度是3的下降子序列。那么1的逆序对有3种,贡献是C(3, 2) = 3种,最后ans = 4是对的。

    这个方法思路很清晰,也很好理解,是bit + 组合数学,意思就是在前面m个数字选出k - 1个,形成长度是k的子序列。

    但是这里忽略了16、19、11,k = 3这样的情况,因为虽然11的逆序对是2,能对答案造成贡献,但是这里11的逆序对互相不能形成逆序对。所以这样的做法是不行的。

    然后设了很多dp,发现还是这个能做。暴力了一下,这个dp是正确的。

    然后就是怎么优化了。

    希望复杂度是O(nk)

    那么我就需要快速知道,前i个数,有多少个比a[i]大的数字,而且它们产生的下降子序列长度是k。的总和

    bit数组c[k]维护的是下降子序列长度是k时的数字情况。

    具体看看代码。以后写出一个合法的dp,超时的,优化下,想一想有没什么数据结构或者某一维是并不需要关心的,比如浙大的校赛那题。dp就是带技巧的暴力,

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <assert.h>
    #define IOS ios::sync_with_stdio(false)
    using namespace std;
    #define inf (0x3f3f3f3f)
    typedef long long int LL;
    
    
    #include <iostream>
    #include <sstream>
    #include <vector>
    #include <set>
    #include <map>
    #include <queue>
    #include <string>
    #include <bitset>
    const int maxn = 20000 + 20;
    int dp[maxn][100 + 20];
    int a[maxn];
    int c[100 + 2][maxn];
    int n, k;
    const int MOD = 1e9 + 7;
    void add(int &x, int val) {
        x += val;
        if (x >= MOD) x -= MOD;
    }
    int lowbit(int x) {
        return x & (-x);
    }
    void upDate(int pos, int val, int which) {
        while (pos) {
            add(c[which][pos], val);
            pos -= lowbit(pos);
        }
    }
    int ask(int pos, int which) {
        int ans = 0;
        while (pos <= n) {
            add(ans, c[which][pos]);
            pos += lowbit(pos);
        }
        return ans;
    }
    void work() {
        scanf("%d%d", &n, &k);
        memset(c, 0, sizeof c);
        memset(dp, 0, sizeof dp);
        for (int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
        }
        for (int i = 1; i <= n; ++i) {
            dp[i][1] = 1;
            for (int j = 2; j <= k; ++j) {
                add(dp[i][j], ask(a[i] + 1, j - 1));
            }
            for (int j = 1; j <= k; ++j) {
                upDate(a[i], dp[i][j], j);
            }
        }
        int ans = 0;
        for (int i = 1; i <= n; ++i) {
            add(ans, dp[i][k]);
        }
        printf("%d
    ", ans);
    }
    
    int main() {
    #ifdef local
        freopen("data.txt", "r", stdin);
    //    freopen("data.txt", "w", stdout);
    #endif
    //    cout << comb[7][2] << endl;
    //    cout << comb[4][2] << endl;
        int t;
        scanf("%d", &t);
        while (t--) work();
        return 0;
    }
    View Code
  • 相关阅读:
    剖析HBase负载均衡和性能指标
    Hadoop大数据挖掘从入门到进阶实战
    实战Kafka ACL机制
    论文笔记系列--MnasNet:Platform-Aware Neural Architecture Search for Mobile
    在 Vim 中优雅地查找和替换
    VIM的列编辑操作
    理解Pytorch中LSTM的输入输出参数含义
    Python为什么要用抽象类(abc模块)?
    概率密度估计介绍
    Docker永久挂载本地目录
  • 原文地址:https://www.cnblogs.com/liuweimingcprogram/p/6706224.html
Copyright © 2020-2023  润新知