构造排列
内存限制: 256 Mb时间限制: 1000 ms
题目描述
给定一个 nn,请你构造一个长度为 n 的排列p1,p2,...,pn,使得该排列中不存在对于任意的三个参数i,j,k,满足i<j<k、且 pi<pj<pk。
请问对于给定的参数 n ,有多少个长度为 n 的排列满足以上条件。由于答案可能较大,输出对109+7取模的结果即可。
输入格式
输入共一行,一个正整数n
输出格式
输出一个正整数,表示答案
数据范围
- 对于 30% 的数据,1≤n≤10
- 对于 60% 的数据,1≤n≤100
- 对于 100% 的数据,1≤n≤10^4
样例数据
输入:
3
输出:
5
说明:
1,3,2
2,1,3
2,3,1
3,1,2
3,2,1 都可。
只有 1,2,3 不满足条件
解析:搜索可以搞定30%的数据,详见代码:
#include <bits/stdc++.h>
using namespace std;
int n;
int a[10005];
bool b[100005];
int dp[10005];
int ans = 0;
void dfs(int step) {
if (step > n) {
ans++;
return;
}
for(int i = 1; i <= n; i++) {
if (b[i] == 0) {
a[step] = i;
dp[step] = 1;
for(int j = 1; j < step; j++) {
if (a[j] > a[step]) {
dp[step] = max(dp[step], dp[j] + 1);
if (dp[step] >= 3) {
break;
}
}
}
if (dp[step] >= 3) continue;
b[i] = 1;
dfs(step + 1);
b[i] = 0;
}
}
}
int main() {
cin >> n;
dfs(1);
cout << ans;
return 0;
}
正解为卡特兰数,感谢 广州的王淞老师提供的代码:
#include <iostream>
using namespace std;
typedef long long ll;
ll mod = 1e9 + 7;
// 快速幂
ll mi(ll x, ll y) {
ll res = 1;
x = x % mod;
while (y > 0) {
if (y & 1) res = (res * x) % mod;
y = y >> 1;
x = (x * x) % mod;
}
return res;
}
// 计算n的阶乘 取余
ll jc(ll n) {
ll result = 1;
for (ll i = 2; i <= n; i++) {
result = (result * i) % mod;
}
return result;
}
// 计算 C(2n, n) / n+1 取余
ll cul(ll n) {
// C(2n, n) = 2n! / n! / n! / n+1 = 2n! / (n! * (n+1)! )
ll fenzi = jc(2 * n);
ll fenmu = (jc(n) * jc(n + 1)) % mod;
// 使用费马小定理求逆元
return (fenzi * mi(fenmu, mod - 2)) % mod;
}
int main() {
ll n;
cin >> n;
if(n == 1 || n == 2) {
cout << "0" << endl;
return 0;
}
ll ctl = cul(n);
cout << ctl << endl;
return 0;
}