bzoj1925: [Sdoi2010]地精部落
题目链接
题解
波动子序列DP,建议食用luogu题解第一个https://www.luogu.org/problemnew/solution/P2467
f[i,j]表示1到i的排列中第一个数的取值范围是[1,j]且第二个数比第一个数大的数量。
f[i,j]=f[i,j-1]+f[i-1,i-j]
若第一个数为[1,j-1] 则为 f[i,j-1]
若第一个数为j,就相当于求1到 i-1 的排列中第二个数比第一个数小的数量
但根据对称性,这东西相当于f[i,i-j]
滚动数组
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 4207;
int n,p,dp[2][maxn];
int main() {
scanf("%d%d",&n,&p);
int now = 1;
dp[now][1] = 1;
for(int i = 2; i <= n; ++i) {
now ^= 1;
memset(dp[now],0,sizeof dp[now]);
for(int j = 1;j <= i;++ j)
dp[now][j] = (dp[now][j - 1] + dp[now ^ 1][i - j]) % p;
}
int ans = 0;
for(int j = 1; j <= n; ++j) ans = (ans + dp[now][j]) % p;
printf("%d\n", dp[now][n] * 2 % p);
return 0;
}