一道很经典的DP题。

题意:求n排列中波动排列的种数。

不妨考虑DP,令dp1[i][j],表示1-j的排列中,第一项为i之后递增的波动排列种数。dp2[i][j]表示1-j的排列中,第一项为i之后递减的波动排列种数。

显然有一个性质,dp1[i][j]=dp2[j+1-i][j],将各项用j+1减去即可。

所以我们主要观察dp1数组。

如果第一项放了i,之后的数字是1,2,,,i-1,i+1,i+2,,j。

如果我们把大于i的数减去1,就又变成了j-1的一个排列,那么则有dp1[i][j]=sum(dp2[i][j-1]+dp2[i+1][j-1]+...dp2[j-1][j-1]).

因为dp2[i][j]=dp1[j+1-i][j],所以dp1[i][j]=sum(dp1[1][j-1]+dp1[2][j-1]+....+dp1[j-i][j-1]).

可以用前缀和优化转移。用滚动数组优化空间。时间复杂度O(n^2).

# include <cstdio>
# include <cstring>
# include <cstdlib>
# include <iostream>
# include <vector>
# include <queue>
# include <stack>
# include <map>
# include <bitset>
# include <set>
# include <cmath>
# include <algorithm>
using namespace std;
# define lowbit(x) ((x)&(-x))
# define pi acos(-1.0)
# define eps 1e-
# define MOD
# define INF
# define mem(a,b) memset(a,b,sizeof(a))
# define FOR(i,a,n) for(int i=a; i<=n; ++i)
# define FO(i,a,n) for(int i=a; i<n; ++i)
# define bug puts("H");
# define lch p<<,l,mid
# define rch p<<|,mid+,r
# define mp make_pair
# define pb push_back
typedef pair<int,int> PII;
typedef vector<int> VI;
# pragma comment(linker, "/STACK:1024000000,1024000000")
typedef long long LL;
int Scan() {
int x=,f=;char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=-;ch=getchar();}
while(ch>=''&&ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
const int N=;
//Code begin... int dp[][N], sum[N]; int main ()
{
int n, P, flag=;
scanf("%d%d",&n,&P);
dp[][]=; sum[]=;
for (int i=n-; i>=; --i) {
flag^=; mem(dp[flag],);
FOR(j,,n-i+) if (n-i-j>=) dp[flag][j]=sum[n-i-j+];
mem(sum,);
FOR(j,,n-i+) sum[j]=(sum[j-]+dp[flag][j])%P;
}
LL ans=;
FOR(i,,n) ans=(ans+dp[flag][i])%P;
ans=ans*%P;
printf("%lld\n",ans);
return ;
}
05-11 22:52