[BZ1925] [SDOI2010]地精部落

Posted gavinzheng

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZ1925] [SDOI2010]地精部落相关的知识,希望对你有一定的参考价值。

[BZ1925] [SDOI2010]地精部落

传送门

一道很有意思的DP题。

我们发现因为很难考虑每个排列中的数是否使用过,所以我们想到只维护相对关系。

当我们考虑新的一个位置时,给新的位置的数分配一个排名(可以理解为把这个位置的大小插入在原来两个位置的大小的中间)。

所以令\\(dp[i][j][0/1]\\)表示前i个数,第i个数在前i个数中排名为j,最后两个数是上升/下降时的相对关系的方案数。

那么有:
\\[ dp[i][j][0]=\\sum_k=1^j-1dp[i-1][k][1]\\dp[i][j][1]=\\sum_k=j^i-1dp[i-1][k][0]\\dp[1][1][1]=dp[1][1][0]=1; \\]
然后前缀和优化一下:
\\[ f[i][j][0]=\\sum_k=1^jdp[i][j][0]\\f[i][j][1]=\\sum_k=1^jdp[i][j][1]\\\\]
那么转移就是:
\\[ dp[i][j][0]=f[i-1][j-1][1]\\dp[i][j][1]=f[i-1][i-1][0]-f[i-1][j-1][0]\\初始化:f[1][1][0]=f[1][1][1]=1 \\]
代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
const int maxn=4500;
using namespace std;
int n,p;
int dp[2][maxn][2],f[2][maxn][2];
int main() 
    scanf("%d%d",&n,&p);
    dp[1][1][0]=dp[1][1][1]=f[1][1][1]=f[1][1][0]=1;
    for(int i=2;i<=n;i++) 
        int md=i&1;
        for(int j=1;j<=i;j++)dp[md][j][0]=dp[md][j][1]=0;
        for(int j=1;j<=i;j++) 
            dp[md][j][0]+=f[md^1][j-1][1];dp[md][j][0]%=p;
            dp[md][j][1]+=f[md^1][i-1][0]-f[md^1][j-1][0];dp[md][j][1]%=p;
        
        for(int j=1;j<=i;j++) 
            f[md][j][0]=f[md][j-1][0]+dp[md][j][0];f[md][j][0]%=p;
            f[md][j][1]=f[md][j-1][1]+dp[md][j][1];f[md][j][1]%=p;
        
    
    printf("%d",(((f[n&1][n][1]+f[n&1][n][0])%p)+p)%p);

技术图片

以上是关于[BZ1925] [SDOI2010]地精部落的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ 1925][Sdoi2010]地精部落

BZOJ1925: [Sdoi2010]地精部落

BZOJ 1925: [Sdoi2010]地精部落

bzoj 1925 [Sdoi2010]地精部落 dp

[bzoj1925][Sdoi2010]地精部落_递推_动态规划

bzoj1925地精部落[SDOI2010](dp)