序列的计算
题目限制
- 内存限制: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
1≤n≤1000
0
≤
k
≤
n
0 \leq k \leq n
0≤k≤n
思路
这题首先想到的是搜索,但 数据范围不适合 和 无限输入 表明了不可能是搜索
除了搜索,就只能想到递推了
定义
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⋅⋅⋅ai−1,ai=i} 把
a
i
a_i
ai 与 之前的
i
−
1
i - 1
i−1 个数之一 交换得到
对于一种状态 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⋅⋅⋅i−1} 构成 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[i−1][j]∗(j+1)
- 若 集合 { 1 , 2 , 3 ⋅ ⋅ ⋅ i − 1 } \{ 1, 2, 3 ··· i-1 \} {1,2,3⋅⋅⋅i−1} 构成 E E E 值为 j − 1 j - 1 j−1,故 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 (i−1)−(j−1)=i−j 种情况;即 d p [ i − 1 ] [ j − 1 ] ∗ ( i − j ) dp[i - 1][j - 1] * (i - j) dp[i−1][j−1]∗(i−j)
综上所述: 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[i−1][j]∗(j+1)+dp[i−1][j−1]∗(i−j);但是当 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;
}