序列的计算

序列的计算

题目限制

  • 内存限制:128MiB
  • 时间限制:1000ms
  • 标准输入输出

题目知识点

  • 思维
  • 递推
  • 动态规划 d p dp dp

题目

题目背景

有一个集合 { 1 , 2 , 3 , . . . , n } \{ 1, 2, 3, ..., n \} {1,2,3,...,n}
将集合里面的所有元素构成若干个序列 { a 1 , a 2 , a 3 ⋅ ⋅ ⋅ a n } \{ a_1, a_2, a_3 ··· a_n \} {a1,a2,a3⋅⋅⋅an},并且定义 E E E 值为序列中 a i > i a_i > i ai>i 的元素个数

例如:
序列 1 , 3 , 2 , 4 1, 3, 2, 4 1,3,2,4 E E E 值为 1 1 1;其中 a 2 = 3 > 2 a_2 = 3 > 2 a2=3>2
序列 4 , 3 , 2 , 1 4, 3, 2, 1 4,3,2,1 E E E 值为 2 2 2;其中 a 1 = 4 > 1 , a 2 = 3 > 2 a_1 = 4 > 1, a_2 = 3 > 2 a1=4>1,a2=3>2

题目描述

现在给你 n n n k k k,请你找出由集合 { 1 , 2 , 3 , ⋅ ⋅ ⋅ n } \{ 1, 2, 3, ··· n \} {1,2,3,⋅⋅⋅n} 构成的所有序列当中,有多少个序列的 E E E 值为 k k k

格式

本题是无限输入

输入格式

对于每组输入的数据:
输入共 1 1 1 行,包含 2 2 2 个整数 n n n k k k

输出格式

对于每组输入的数据:
输出共 1 1 1 行,包含 1 1 1 个整数,表示答案
有可能答案会非常的大,请输出答案 m o d \mathrm{mod} mod ( 1 e 9 + 7 ) (1e9 + 7) (1e9+7) 的值。

样例

样例输入

3 0
3 1

样例输出

1
4

提示

数据范围

对于 100 % 100\% 100% 的数据:
1 ≤ n ≤ 1000 1 \leq n \leq 1000 1n1000
0 ≤ k ≤ n 0 \leq k \leq n 0kn


思路

这题首先想到的是搜索,但 数据范围不适合无限输入 表明了不可能是搜索
除了搜索,就只能想到递推了

定义 d p [ i ] [ j ] dp[i][j] dp[i][j] 表示:用 集合 { 1 , 2 , 3 ⋅ ⋅ ⋅ i } \{ 1, 2, 3 ··· i \} {1,2,3⋅⋅⋅i} 能构成 E E E 值为 k k k 的序列个数
记 用集合 { 1 , 2 , 3 ⋅ ⋅ ⋅ i } \{ 1, 2, 3 ··· i \} {1,2,3⋅⋅⋅i} 构成的序列为 a a a
可以发现, a a a 所构成的任意一种序列 { a 1 , a 2 , a 3 ⋅ ⋅ ⋅ a i } \{ a_1, a_2, a_3 ··· a_i \} {a1,a2,a3⋅⋅⋅ai} 都可以通过 { a 1 , a 2 , a 3 ⋅ ⋅ ⋅ a i − 1 , a i = i } \{ a_1, a_2, a_3 ··· a_{i-1}, a_i = i \} {a1,a2,a3⋅⋅⋅ai1,ai=i} a i a_i ai 与 之前的 i − 1 i - 1 i1 个数之一 交换得到

对于一种状态 d p [ i ] [ j ] dp[i][j] dp[i][j],由于 a i a_i ai 只能贡献 0 0 0 1 1 1,所以有 2 2 2 种情况:

  • 若 集合 { 1 , 2 , 3 ⋅ ⋅ ⋅ i − 1 } \{ 1, 2, 3 ··· i-1 \} {1,2,3⋅⋅⋅i1} 构成 E E E 值为 j j j,故 a i a_i ai 是不做贡献的;当前 集合是 { a 1 , a 2 , a 3 ⋅ ⋅ ⋅ a i = i } \{ a_1, a_2, a_3 ··· a_i = i \} {a1,a2,a3⋅⋅⋅ai=i} a i a_i ai 只能 不交换 或者 与前面已经做了贡献的位置交换,故有 j + 1 j + 1 j+1 种情况;即 d p [ i − 1 ] [ j ] ∗ ( j + 1 ) dp[i - 1][j] * (j + 1) dp[i1][j](j+1)
  • 若 集合 { 1 , 2 , 3 ⋅ ⋅ ⋅ i − 1 } \{ 1, 2, 3 ··· i-1 \} {1,2,3⋅⋅⋅i1} 构成 E E E 值为 j − 1 j - 1 j1,故 a i a_i ai 是做贡献的;当前 集合是 { a 1 , a 2 , a 3 ⋅ ⋅ ⋅ a i = i } \{ a_1, a_2, a_3 ··· a_i = i \} {a1,a2,a3⋅⋅⋅ai=i} a i a_i ai 只能 与前面已经没做贡献的位置交换,故有 ( i − 1 ) − ( j − 1 ) = i − j (i - 1) - (j - 1) = i - j (i1)(j1)=ij 种情况;即 d p [ i − 1 ] [ j − 1 ] ∗ ( i − j ) dp[i - 1][j - 1] * (i - j) dp[i1][j1](ij)

综上所述: d p [ i ] [ j ] = d p [ i − 1 ] [ j ] ∗ ( j + 1 ) + d p [ i − 1 ] [ j − 1 ] ∗ ( i − j ) dp[i][j] = dp[i - 1][j] * (j + 1) + dp[i - 1][j - 1] * (i - j) dp[i][j]=dp[i1][j](j+1)+dp[i1][j1](ij);但是当 j = 0 j = 0 j=0 的时候,序列 a a a 只有 { 1 , 2 , 3 ⋅ ⋅ ⋅ i } \{ 1, 2, 3 ··· i \} {1,2,3⋅⋅⋅i} 一种方案


分析

由于 a a a 这个序列只包含元素 { 1 , 2 , 3 , . . . , i } \{ 1, 2, 3, ..., i \} {1,2,3,...,i},与其它数无关; d p [ i ] [ j ] dp[i][j] dp[i][j] 也只与 i , j i, j i,j 有关
我们可以先预处理出 d p dp dp,输入 n n n k k k 之后直接输出 d p [ n ] [ k ] dp[n][k] dp[n][k] 即可

for (int i = 1; i <= MAXN; i++)
{
	for (int j = 0; j < i; j++) // E值 不可能超过 i, 而且不可能有 j >= i 的序列 
	{
		if (j == 0) { dp[i][j] = 1LL; continue; }
		dp[i][j] = (dp[i][j] + dp[i - 1][j] * (j + 1)) % MOD;
		dp[i][j] = (dp[i][j] + dp[i - 1][j - 1] * (i - j) % MOD) % MOD;
	}
}

代码

#include <cstdio>

#define i32 int
#define i64 long long
#define u32 unsigned i32
#define u64 unsigned i64

const int MOD = 1e9 + 7;
const int MAXN = 1e3, MAXK = MAXN;
int N, K;
i64 dp[MAXN + 5][MAXK + 5];

int main()
{
	for (int i = 1; i <= MAXN; i++)
	{
		for (int j = 0; j < i; j++)
		{
			if (j == 0) { dp[i][j] = 1LL; continue; }
			dp[i][j] = (dp[i][j] + dp[i - 1][j] * (j + 1)) % MOD;
			dp[i][j] = (dp[i][j] + dp[i - 1][j - 1] * (i - j) % MOD) % MOD;
		}
	}
	while (scanf("%d %d", &N, &K) != EOF)
		printf("%lld\n", dp[N][K]);
	return 0;
}


“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值