题目链接:https://zhixincode.com/contest/18/problem/G?problem_id=265
题目描述
wls有一个整数 $n$,他想请你算一下有多少 $1...n$ 的排列(permutation)满足:对于所有的 $i(2 le i le n)$,若 $i$ 为奇数,则 $a[i−1]<a[i]$,否则 $a[i−1]>a[i]$。请输出答案 $mod 1e9 + 7$。
输入描述
一行一个整数 $n$。
$1≤n≤1000$
输出描述
一行一个整数表示答案。
样例输入 1
3
样例输出 1
2
题解:
这个数大概叫 up/down number ?参见OEIS:https://oeis.org/A000111
$dp[i][j]$ 表示前 $i$ 个满足字符串条件的结尾为 $j$ 的 $i$ 的排列,这里需要注意的是 $1 sim i$ 的排列。
那么,如果第 $i$ 位是奇数位(山峰),$dp[i][j] = dp[i-1][1] + dp[i-1][2] + cdots + dp[i-1][j-1]$。这个是很明显的。
那么,如果第 $i$ 位是偶数位(山谷),$dp[i][j] = dp[i-1][j] + dp[i-1][j+1] + cdots + dp[i-1][i-1]$。因为要令当前位为 $j$,那么如果前面出现过大于等于 $j$ 的数字,就令这些数字全部加上 $1$,就能构造出排列。
这样的话,枚举 $i$,然后枚举 $j$,对于每个 $dp[i][j]$ 还需要 $O(n)$ 计算,这样一来就是 $O(n^3)$ 的时间复杂度,用前缀和可以优化到 $O(n^2)$。
AC代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn=1005; const int mod=1e9+7; int n; ll dp[maxn][maxn],sum[maxn][maxn]; int main() { cin>>n; sum[1][1]=dp[1][1]=1; for(int i=2;i<=n;i++) { for(int j=1;j<=i;j++) { if(i%2) //奇数 { dp[i][j]=sum[i-1][j-1]; sum[i][j]=sum[i][j-1]+dp[i][j], sum[i][j]%=mod; } else //偶数 { dp[i][j]=(sum[i-1][i-1]-sum[i-1][j-1]+mod)%mod; sum[i][j]=sum[i][j-1]+dp[i][j], sum[i][j]%=mod; } } } cout<<sum[n][n]<<endl; }