题目

题目描述

JSZKC is the captain of the lala team. 
There are N girls in the lala team. And their height is [1,N] and distinct. So it means there are no two girls with a same height. 
JSZKC has to arrange them as an array from left to right and let h[i] be the height of the ith girl counting from the left. After that, he can calculate the sum of the inversion pairs. A inversion pair counts if h[i]>h[j] with i

输入

The input file contains several test cases, each of them as described below. 
The first line of the input contains two integers N and K (1 ≤ N ≤ 5000, 0 ≤ K ≤ 5000), giving the number of girls and the pairs that JSZKC asked. 
There are no more than 5000 test cases.

输出

An integer in one line for each test case, which is the number of the plans mod 1000000007.

样例输入

  1. 3 2
  2. 3 3
  • 1
  • 2

样例输出

  1. 2
  2. 1
  • 1
  • 2

题意

  问你1~n的所有排列中有多少种排列拥有k对逆序数。

分析:

dp[i][j]代表长度为ii的排列有jj对逆序数的方案数,考虑放第ii个数的时候,前面i−1i−1个数的所有方案都已知,且都比ii小,如果ii放在前i−1i−1个数的最左边,则会新产生i−1i−1对逆序数,如果ii放在前i−1i−1个数的最右边,则不会产生逆序数。也就是说在前i−1i−1个数已经固定,准备放置第ii个数时,可以产生的逆序数对的数量x∈[0,i−1]x∈[0,i−1],于是有:

 

  题目只给了64MB64MB说的内存,所以需要把询问离线下来,然后用滚动数组求解同时离线答案。

参考博客:https://blog.csdn.net/xs18952904/article/details/80597966

AC代码:

  1. #include <map>
  2. #include <set>
  3. #include <stack>
  4. #include <cmath>
  5. #include <queue>
  6. #include <cstdio>
  7. #include <vector>
  8. #include <string>
  9. #include <cstring>
  10. #include <iomanip>
  11. #include <iostream>
  12. #include <algorithm>
  13. #define debug(a) cout << #a << " " << a << endl
  14. using namespace std;
  15. const int maxn = 5*1e3;
  16. const int mod = 1e9 + 7;
  17. typedef long long ll;
  18. ll dp[3][maxn+10], ans[maxn+10], cnt = 0, cur = 0;
  19. struct node {
  20. ll n, k, index;
  21. };
  22. node query[maxn+10];
  23. bool cmp( node p, node q ) {
  24. return p.n < q.n;
  25. }
  26. int main() {
  27. std::ios::sync_with_stdio(false);
  28. while( cin >> query[cnt].n >> query[cnt].k ) {
  29. query[cnt].index = cnt;
  30. cnt ++;
  31. }
  32. sort( query, query+cnt, cmp );
  33. dp[0][0] = 1;
  34. for( ll i = 1; i <= maxn; i ++ ) {
  35. ll sum = 0;
  36. for( ll j = 0; j <= maxn; j ++ ) {
  37. sum = ( sum + dp[i-1&1][j] ) % mod;
  38. if( j-i >= 0 ) {
  39. sum = ( sum - dp[i-1&1][j-i] + mod ) % mod;
  40. }
  41. dp[i&1][j] = sum;
  42. }
  43. while( cur < cnt && query[cur].n == i ) {
  44. ans[query[cur].index] = dp[i&1][query[cur].k];
  45. cur ++;
  46. }
  47. }
  48. for( ll i = 0; i < cnt; i ++ ) {
  49. cout << ans[i] << endl;
  50. }
  51. return 0;
  52. }

  

最后贴一下关于滚动数组的知识:

滚动数组的作用在于优化空间,主要应用在递推或动态规划中(如01背包问题)。因为DP题目是一个自底向上的扩展过程,我们常常需要用到的是连续的解,前面的解往往可以舍去。所以用滚动数组优化是很有效的。利用滚动数组的话在N很大的情况下可以达到压缩存储的作用。

一个简单的例子:

斐波那契数列:

  1. int main()
  2. {
  3. int i;
  4. long long d[80];
  5. d[0] = 1;
  6. d[1] = 1;
  7. for(i = 2; i < 80; i++)
  8. {
  9. d[i] = d[i - 1] + d[i - 2];
  10. }
  11. printf("%lld\n",d[79]);
  12. return 0;
  13. }

  

  1. 上面这个循环d[i]只依赖于前两个数据d[i - 1]和d[i - 2]; 为了节约空间用滚动数组的做法。
  1. int Fib[3];
  2.  
  3. int fib(int n)
  4. {
  5. Fib[1] = 0;
  6. Fib[2] = 1;
  7. for(int i = 2; i <= n; ++i)
  8. {
  9. Fib[0] = Fib[1];
  10. Fib[1] = Fib[2];
  11. Fib[2] = Fib[0] + Fib[1];
  12. }
  13. return Fib[2];
  14. }

  

  1. int main()
  2. {
  3. int i;
  4. long long d[3];
  5. d[0] = 1;
  6. d[1] = 1;
  7. for(i = 2; i < 80; i++)
  8. {
  9. d[i % 3] = d[(i - 1) % 3] + d[(i - 2) % 3];
  10. }
  11. printf("%lld\n", d[79%3]);
  12. return 0;
  13. }

  

  1. 上面的取余运算,我们成功地只保留了需要的最后3个解,数组好象在“滚动”一样,所以叫滚动数组(对于二维也可以用)。
    所以,很明显,滚动数组可以通过取余(%)来实现的,(实现一个滚动|循环)
    但是这里存在一个通病,那就是时间换内存一定会牺牲时间。因此,滚动数组一般用在时间比较充裕,而内存不够的情况下。

滚动数组实际是一种节省空间的办法,时间上没啥优势,多用于DP中,举个例子吧:

一个DP,平常如果需要1000×1000的空间,其实根据DP的无后效性,可以开成2×1000,然后通过滚动,获得和1000×1000一样的效果。滚动数组常用于DP之中,在DP过程中,我们在由一个状态转向另一个状态时,很可能之前存储的某些状态信息就已经无用了,例如在01背包问题中,从理解角度讲我们应开DP[i][j]的二维数组,第一维我们存处理到第几个物品,也就是阶段了,第二维存储容量,但是我们获得DP[i],只需使用DP[i - 1]的信息,DP[i - k],k>1都成了无用空间,因此我们可以将数组开成一维就行,迭代更新数组中内容,滚动数组也是这个原理,目的也一样,不过这时候的问题常常是不可能缩成一维的了,比如一个DP[i][j]需要由DP[i - 1 ][k],DP[i - 2][k]决定,i<n,0<k<=10;n <= 100000000;显然缩不成一维,正常我们应该开一个DP[100000005][11]的数组,结果很明显,超内存,其实我们只要开DP[3][11]就够了DP[i%3][j]由DP[(i - 1)%3][k]和DP[(i - 2)%3][k]决定,空间复杂度差别巨大。

参考博客

https://www.cnblogs.com/kimsimple/p/6883871.html

江苏 徐州邀请赛 icpc B Array dp 滚动数组模板的更多相关文章

  1. HDU 5119 Happy Matt Friends (背包DP + 滚动数组)

    题目链接:HDU 5119 Problem Description Matt has N friends. They are playing a game together. Each of Matt ...

  2. HDU 1024 Max Sum Plus Plus --- dp+滚动数组

    HDU 1024 题目大意:给定m和n以及n个数,求n个数的m个连续子系列的最大值,要求子序列不想交. 解题思路:<1>动态规划,定义状态dp[i][j]表示序列前j个数的i段子序列的值, ...

  3. POJ 3666 Making the Grade (DP滚动数组)

    题意:农夫约翰想修一条尽量平缓的路,路的每一段海拔是A[i],修理后是B[i],花费|A[i] – B[i]|,求最小花费.(数据有问题,代码只是单调递增的情况) #include <stdio ...

  4. USACO 2009 Open Grazing2 /// DP+滚动数组oj26223

    题目大意: 输入n,s:n头牛 s个栅栏 输入n头牛的初始位置 改变他们的位置,满足 1.第一头与最后一头的距离尽量大 2.相邻两头牛之间的距离尽量满足 d=(s-1)/(n-1),偏差不超过1 3. ...

  5. 2014年北京 happy matt friends(dp + 滚动数组优化)

    Happy Matt Friends Time Limit: 6000/6000 MS (Java/Others)    Memory Limit: 510000/510000 K (Java/Oth ...

  6. BZOJ-1925 地精部落 烧脑DP+滚动数组

    1925: [Sdoi2010]地精部落 Time Limit: 10 Sec Memory Limit: 64 MB Submit: 1053 Solved: 633 [Submit][Status ...

  7. Codeforces 712 D. Memory and Scores (DP+滚动数组+前缀和优化)

    题目链接:http://codeforces.com/contest/712/problem/D A初始有一个分数a,B初始有一个分数b,有t轮比赛,每次比赛都可以取[-k, k]之间的数,问你最后A ...

  8. hdu 1513 && 1159 poj Palindrome (dp, 滚动数组, LCS)

    题目 以前做过的一道题, 今天又加了一种方法 整理了一下..... 题意:给出一个字符串,问要将这个字符串变成回文串要添加最少几个字符. 方法一: 将该字符串与其反转求一次LCS,然后所求就是n减去 ...

  9. 【BZOJ】1925: [Sdoi2010]地精部落 DP+滚动数组

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1925 题意:输入一个数N(1 <= N <= 4200),问将这些数排列成折线 ...

随机推荐

  1. 【SQL数据库设计】数据库设计【小型数据库】

    数据库设计 需求 表结构 字段类型.是否允许为null.是否有默认值 索引设计 数据库引擎的选择 根据产品原型分析,词性分析法,名词创建表或字段,动词表示关系. 数据存储:长期存储的数据, 1.主键: ...

  2. Thinkphp5.0快速入门笔记(1)

    学习来源与说明 https://www.kancloud.cn/thinkphp/thinkphp5_quickstart 测试与部署均在windows10下进行学习. Composer安装和更新 C ...

  3. springMVC(一) --前端控制器(DispatcherServlet)的作用

        SpringMVC是Spring中的模块,它实现了mvc设计模式的web框架,首先用户发出请求,请求到达SpringMVC的前端控制器(DispatcherServlet),前端控制器根据用户 ...

  4. Kafka基本知识入门(一)

    1. 基础知识 有关RabbitMQ,RocketMQ,Kafka的区别这个网上很多,了解一下区别性能,分清什么场景使用.分布式环境下的消息中间件Kafka做的比较不错,在分布式环境下使用频繁,我也不 ...

  5. java并发编程(十五)----(线程池)java线程池简介

    好的软件设计不建议手动创建和销毁线程.线程的创建和销毁是非常耗 CPU 和内存的,因为这需要 JVM 和操作系统的参与.64位 JVM 默认线程栈是大小1 MB.这就是为什么说在请求频繁时为每个小的请 ...

  6. LeetCode——409. Longest Palindrome

    题目: Given a string which consists of lowercase or uppercase letters, find the length of the longest ...

  7. php 中session_set_cookie_params 和 setcookie 函数的区别与用法

    session_set_cookie_params() 函数不管刷不刷新页面,都不会改变cookie的过期时间, 但setcookie() 函数页面每刷新一次,cookie 的过期时间就会刷新一次. ...

  8. Java-Servlet请求方式doXXX、service 具体分析

    说起Servlet的接收处理请求的方式,想必各位都并不陌生,如doGet.doPost.service... 那么他们的背后是如何执行?服务器怎么选择知道的?我们就此来探讨一下 本节案例的代码奉上: ...

  9. springboot整合solr

    上一篇博客中简要写了solr在windows的安装与配置,这一篇接上文写一下springboot整合solr,代码已经上传到github,传送门. 1.新建core并配置schema 上篇博客中已经有 ...

  10. 定时清理docker私服镜像

    定时清理docker私服镜像 使用CI构建docker镜像进行发布极大促进了大家的版本发布效率,于是镜像仓库也就急速膨胀.为了缓解磁盘压力,我们需要设置一些清理策略. 对于不同docker镜像的清理策 ...