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

使得1≤l1<l2<...<lk≤n,并且有al1>al2>...>alk

输入

输入有多组数据

第一行是一个正整数T,1≤T≤15,代表数据组数

每组数据第一行是两个正整数n,k,1≤n≤2∗104,1≤k≤min(n,100)

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

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

输出

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

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

样例输入1 复制

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
样例输出1

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 = + ;
int dp[maxn][ + ];
int a[maxn];
int c[ + ][maxn];
int n, k;
const int MOD = 1e9 + ;
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 = ;
while (pos <= n) {
add(ans, c[which][pos]);
pos += lowbit(pos);
}
return ans;
}
void work() {
scanf("%d%d", &n, &k);
memset(c, , sizeof c);
memset(dp, , sizeof dp);
for (int i = ; i <= n; ++i) {
scanf("%d", &a[i]);
}
for (int i = ; i <= n; ++i) {
dp[i][] = ;
for (int j = ; j <= k; ++j) {
add(dp[i][j], ask(a[i] + , j - ));
}
for (int j = ; j <= k; ++j) {
upDate(a[i], dp[i][j], j);
}
}
int ans = ;
for (int i = ; i <= n; ++i) {
add(ans, dp[i][k]);
}
printf("%d\n", 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 ;
}

wmq的队伍 BIT优化dp的更多相关文章

  1. bzoj-4518 4518: [Sdoi2016]征途(斜率优化dp)

    题目链接: 4518: [Sdoi2016]征途 Description Pine开始了从S地到T地的征途. 从S地到T地的路可以划分成n段,相邻两段路的分界点设有休息站. Pine计划用m天到达T地 ...

  2. bzoj-1096 1096: [ZJOI2007]仓库建设(斜率优化dp)

    题目链接: 1096: [ZJOI2007]仓库建设 Description L公司有N个工厂,由高到底分布在一座山上.如图所示,工厂1在山顶,工厂N在山脚.由于这座山处于高原内陆地区(干燥少雨),L ...

  3. 【Codeforces720D】Slalom 线段树 + 扫描线 (优化DP)

    D. Slalom time limit per test:2 seconds memory limit per test:256 megabytes input:standard input out ...

  4. 单调队列优化DP,多重背包

    单调队列优化DP:http://www.cnblogs.com/ka200812/archive/2012/07/11/2585950.html 单调队列优化多重背包:http://blog.csdn ...

  5. [BZOJ3156]防御准备(斜率优化DP)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=3156 分析: 简单的斜率优化DP

  6. 【BZOJ-1096】仓库建设 斜率优化DP

    1096: [ZJOI2007]仓库建设 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3719  Solved: 1633[Submit][Stat ...

  7. 优化DP的奇淫技巧

    DP是搞OI不可不学的算法.一些丧心病狂的出题人不满足于裸的DP,一定要加上优化才能A掉. 故下面记录一些优化DP的奇淫技巧. OJ 1326 裸的状态方程很好推. f[i]=max(f[j]+sum ...

  8. bzoj1855: [Scoi2010]股票交易--单调队列优化DP

    单调队列优化DP的模板题 不难列出DP方程: 对于买入的情况 由于dp[i][j]=max{dp[i-w-1][k]+k*Ap[i]-j*Ap[i]} AP[i]*j是固定的,在队列中维护dp[i-w ...

  9. BZOJ 1010: [HNOI2008]玩具装箱toy 斜率优化DP

    1010: [HNOI2008]玩具装箱toy Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再 ...

随机推荐

  1. OSI和TCP/IP

    OSI和TCP/IP 1.        OSI的七层网络结构(功能及特点) 1)  物理层:为数据链路层提供物理连接,在其上串行传送比特流,即所传送数据的单位是比特.此外,该层中还具有确定连接设备的 ...

  2. IOS开发学习笔记(1)-----UILabel 详解

    1. [代码][C/C++]代码     //创建uilabelUILabel *label1 = [[UILabel alloc] initWithFrame:CGRectMake(20, 40, ...

  3. linux应用之samba服务的安装及配置(centos)

    一.安装方式: 本文通过yum来重新进行Samba服务器的安装与配置. 二.Samba的简介: Samba是一个能让Linux系统应用Microsoft网络通讯协议的软件,而SMB是Server Me ...

  4. Git学习笔记 - Git安装

    Git安装(Windows) 从 https://git-for-windows.github.io/ 下载Git,下载完成,双击安装,一路选择默认设置即可. 注意:选择使用git的命令行模式,选择默 ...

  5. linux内存占用分析

    概述 想必在linux上写过程序的同学都有分析进程占用多少内存的经历,或者被问到这样的问题——你的程序在运行时占用了多少内存(物理内存)?通常我们可以通过top命令查看进程占用了多少内存.这里我们可以 ...

  6. 使用weui

    1 在https://github.com/weui/weui-wxss/下载项目,得到weui.wxss文件 2 把文件放在小程序项目的根目录下 3 在app.wxss中引用weui.wxss文件 ...

  7. JSP提交表单的几种方法

    1.通过<form action="url"><input type="submit"></form>按钮方式提交 这种方式 ...

  8. 理解复杂的const和typedef和指针的关系

    // container.cpp : 定义控制台应用程序的入口点. //   #include "stdafx.h" #include<iostream> #inclu ...

  9. monkey之monkeyServer

    基本命令: adb shell monkey --port 1080 & adb forward tcp:1080 tcp:1080 telnet 127.0.0.1 1080 启动andro ...

  10. 【Linux学习】Linux用户管理2—用户配置文件

    Linux用户管理2-用户配置文件 /etc/passwd: 存放系统用户的文件 输入 vi /etc/passwd /etc/shadow: 保存保密文件 /etc/group: 群组文件 输入 v ...