51nod1020 逆序排列(dp)

1020 逆序排列

基准时间限制:2 秒 空间限制:131072 KB 分值: 80 难度:5级算法题

收藏

关注

在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。

如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。

1-n的全排列中,逆序数最小为0(正序),最大为n*(n-1) / 2(倒序)

给出2个数n和k,求1-n的全排列中,逆序数为k的排列有多少种?

例如:n = 4 k = 3。

1 2 3 4的排列中逆序为3的共有6个,分别是:

1 4 3 2

2 3 4 1

2 4 1 3

3 1 4 2

3 2 1 4

4 1 2 3

由于逆序排列的数量非常大,因此只需计算并输出该数 Mod 10^9 + 7的结果就可以了。

Input

第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 10000)
第2 - T + 1行:每行2个数n,k。中间用空格分隔。(2 <= n <= 1000, 0 <= k <= 20000)

Output

共T行,对应逆序排列的数量 Mod (10^9 + 7)

Input示例

1
4 3

Output示例

6

设f(n,k)表示n个数的排列中逆序数个数为k的排列数。

最大的数n可能会排在第n-i位,从而产生i个与n有关的逆序对,去掉n之后,剩下的n-1个数的排列有k-i个逆序对。所以,f(n,k)=求和(f(n-1,k-i))(0<=i<n)。

同理有f(n,k-1)=求和(f(n-1,k-1-i))(0<=i<n)。

两式相减,可得f(n,k)-f(n,k-1)=f(n-1,k)-f(n-1,k-n)。

递推公式为f(n,k)=f(n,k-1)+f(n-1,k)-f(n-1,k-n)。

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <string>
#include <functional>
#include <cmath>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <stack>
using namespace std;
#define esp  1e-8
const double PI = acos(-1.0);
const double e = 2.718281828459;
const int inf = 2147483647;
const long long mod = 1000000007;
typedef long long ll;
//freopen("in.txt","r",stdin); //输入重定向,输入数据将从in.txt文件中读取
//freopen("out.txt","w",stdout); //输出重定向,输出数据将保存在out.txt文件中
int dp[1005][20005];
void init()
{
	for (int i = 1; i <= 1000; ++i)
		dp[i][0] = 1;
	for (int i = 2; i <= 1000; ++i)
	{
		for (int j = 1; j <= i * (i - 1) / 2 && j <= 20000; ++j)
		{
			dp[i][j] = (dp[i][j - 1] + dp[i - 1][j]) % mod;
			if (j - i >= 0)
				dp[i][j] -= dp[i - 1][j - i];
			dp[i][j] = (dp[i][j] % mod + mod) % mod;
		}
	}
}
int main()
{
	int t, n, k;
	init();
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d", &n, &k);
		printf("%d\n", dp[n][k]);
	}

}
时间: 2024-10-24 09:04:08

51nod1020 逆序排列(dp)的相关文章

51Nod 1020 逆序排列

 1020 逆序排列 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中逆序的总数就称为这个排列的逆序数. 如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4. 1-n的全排列中,逆序数最小为0(正序),最大为n*(n-1) / 2(倒序) 给出2个数n和k,求1-n的全排列中,逆序数为k的排列有多少种? 例如:n = 4 k = 3. 1 2 3 4的排列中逆序为3的共有6个,分别是: 1 4 3 2 2 3 4 1

算法题:一个N字节的数,如何逆序排列各个位(bit)?例如1字节的数 0010 0011 =&gt; 1100 0100

一个简简单单的题,如果用Java,C++,C估计还挺麻烦的,大体思路就是,开辟个N字节空间,用移位掩码方法逆向给每个bit赋值,这里由于N可能比较大,还得记录些额外的边界信息. 用Erlang则会简单很多: -module(bitoperator). -export([bit_reverse/1]). bit_reverse(Bin) -> L = [X || <<X:1>> <= Bin], Lr = lists:reverse(L), Br = list_to_bi

10.14 将n个数按输入输出顺序的逆序排列,用函数实现

将n个数按输入输出顺序的逆序排列,用函数实现. #include <stdio.h> int main(){ int n,i; void reverse(int * num, int n); printf("input n="); scanf("%d",&n); int num[20]; printf("输入%d个数.\n",n); for(i=0; i<n; i++){ scanf("%d",&am

蓝桥杯- 算法提高 逆序排列

算法提高 逆序排列 时间限制:1.0s   内存限制:512.0MB 问题描述 编写一个程序,读入一组整数(不超过20个),并把它们保存在一个整型数组中.当用户输入0时,表示输入结束.然后程序将把这个数组中的值按逆序重新存放,并打印出来.例如:假设用户输入了一组数据:7 19 -5 6 2 0,那么程序将会把前五个有效数据保存在一个数组中,即7 19 -5 6 2,然后把这个数组中的值按逆序重新存放,即变成了2 6 -5 19 7,然后把它们打印出来. 输入格式:输入只有一行,由若干个整数组成,

算法笔记_158:算法提高 逆序排列(Java)

目录 1 问题描述 2 解决方案 1 问题描述 问题描述 编写一个程序,读入一组整数(不超过20个),并把它们保存在一个整型数组中.当用户输入0时,表示输入结束.然后程序将把这个数组中的值按逆序重新存放,并打印出来.例如:假设用户输入了一组数据:7 19 -5 6 2 0,那么程序将会把前五个有效数据保存在一个数组中,即7 19 -5 6 2,然后把这个数组中的值按逆序重新存放,即变成了2 6 -5 19 7,然后把它们打印出来. 输入格式:输入只有一行,由若干个整数组成,中间用空格隔开,最末尾

逆序排列

/** 例子输入 7 19 -5 6 2 0 例子输出 2 6 -5 19 7 */ import java.util.*; import java.io.*; public class 逆序排列 { public static void main(String[] args) { Scanner in=new Scanner(new BufferedInputStream(System.in)); int [] a=new int [21]; int num=0; a[0]=in.nextIn

算法之链表逆序排列

算法纯属个人爱好,欢迎交流,共享 /** * */ package com.zimo.sequence; /** * 逆序排列 * @author 子墨 * * 2015-3-11下午2:31:55 */ public class Node { int data; Node next = null; public Node(int data){ this.data=data; } /** * 1->2->3->4->5->6->7->8->9 * 定义一个p

51nod 1020 逆序排列(动态规划)

分析:记dp[n][k]为n个数,逆序数为k的个数,将dp[n][k]分为两部分,一部分有1~n-1的逆序构成,一类是有n的逆序,可以得到dp[n+1][k+1]=(max(0,k+1-n),min(k+1,n*(n-1)/2)∑dp[n][i],再用dp[n+1][k+1]与dp[n+1][k]做差,讨论一下k和n的关系就可以写出递推式了. 1 #include<iostream> 2 using namespace std; 3 const int maxn=1005,maxk=20005

Java数组逆序排列

public class Test4 { public static void main(String[] args) { //数组的逆序 {12,69,852,25,89,588} int[] arr = {12,69,852,25,89,588}; reverse(arr); printArray(arr);} public static void reverse(int[] arr){ for(int min =0,max=arr.length-1;min<max;min++,max--)