题意
我们把一个数称为有趣的,当且仅当:
- 它的数字只包含 (0,1,2,3),且这四个数字都出现过至少一次。
- 所有的 (0) 都出现在所有的 (1) 之前,而所有的 (2) 都出现在所有的 (3) 之前。
- 最高位数字不为 (0)。
因此,符合我们定义的最小的有趣的数是 (2013)。
除此以外,(4) 位的有趣的数还有两个:(2031) 和 (2301)。
请计算恰好有 (n) 位的有趣的数的个数。
由于答案可能非常大,只需要输出答案除以 (10^9+7) 的余数。
数据范围
(4 leq n leq 1000)
思路
感觉这道题的题目描述挺像高中数学排列组合题的,因此先考虑组合计数方法。
组合计数题通常的思考方式就是分类讨论。这道题可以将(0,1)看成一组,(2,3)看成一组,一组的数量确定了,另一组的数量也就跟着确定了。
因此,我们可以分类讨论(0,1)组的数量。因为每个数组都至少出现过(1)次,因此(0,1)组的数量可以是(2 sim n - 2)中的任意数。
假设数量是(k),那么就从(n - 1)位(第一位不能选)选(k)位,因此就是(C_{n - 1}^k)种。
然后再讨论每个数具体个数,那么(0)可能有(1 sim k - 1),因此就有(k - 1)种情况;对应的,(2)可能有(1 sim n - k - 1),因此就有(n - k - 1)种可能。
因此,最终的答案为:
[sum_{k = 2}^{n - 2} C_{n - 1}^k * (k - 1) * (n - k - 1)
]
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1010, mod = 1e9 + 7;
int n;
ll c[N][N];
int main()
{
scanf("%d", &n);
for(int i = 0; i <= n; i ++) {
for(int j = 0; j <= i; j ++) {
if(!j) c[i][j] = 1;
else c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod;
}
}
ll ans = 0;
for(int i = 2; i <= n - 2; i ++) {
ans = (ans + c[n - 1][i] * (i - 1) * (n - i - 1)) % mod;
}
printf("%lld
", ans);
return 0;
}