zoukankan      html  css  js  c++  java
  • [BZ1925] [SDOI2010]地精部落

    [BZ1925] [SDOI2010]地精部落

    传送门

    一道很有意思的DP题。

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

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

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

    那么有:

    [dp[i][j][0]=sum_{k=1}^{j-1}dp[i-1][k][1]\ dp[i][j][1]=sum_{k=j}^{i-1}dp[i-1][k][0]\ dp[1][1][1]=dp[1][1][0]=1; ]

    然后前缀和优化一下:

    [f[i][j][0]=sum_{k=1}^{j}dp[i][j][0]\ f[i][j][1]=sum_{k=1}^{j}dp[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);
    }
    

  • 相关阅读:
    [转载]c++转python
    [转载]One-hot编码
    [转载]各种机器学习算法的应用场景
    SVC和SVR
    机器学习-正则化+回归与分类辨析
    C#编译时,提示缺少NuGet包
    C++中 左值和右值的区别
    C++11并发编程实战 免费书籍
    静态库和动态库
    C++中string类
  • 原文地址:https://www.cnblogs.com/GavinZheng/p/11620731.html
Copyright © 2011-2022 走看看