zoukankan      html  css  js  c++  java
  • [题解]luogu_P2467_地精部落(思维dp

    前言:不说废话,野狼disco牛逼就完事了(网易云和b站绝对共享cookie


    这题喵啊.....好多解法慢慢写吧...

    1.一种优秀且优雅的组合数解法

    首先发现一个性质,先下降和先上升序列一样多,只要把每个点取反就可以,所以我们可以只计算一种

    例如我们计算先下降的序列,考虑往后加入$i$,那么一定是加到奇数位置,左右只要和$i$组合起来合法就可以,若加入$j$位置,那么左边可以放$j-1$个,右面可以放$i-j$个,答案乘上$f[j-1]*f[i-j]$,注意这里其实相当于是把数字离散化了,所以还要考虑数字分配问题,把$i-1$个数选$j-1$个分给左边,乘上$c[i-1][j-1]$,卡空间滚动数组求组合数

    抄的代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    const int maxn=4209;
    ll f[maxn],c[2][maxn],p,n;
    int main(){
        scanf("%d%d",&n,&p);c[0][0]=c[1][0]=f[0]=1;
        for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++){
            if(j&1)(f[i]+=(f[j-1]*f[i-j]%p)*(c[(i-1)&1][j-1]%p))%=p;
            c[i&1][j]=(c[(i-1)&1][j]+c[(i-1)&1][j-1]%p)%p;
        }
        printf("%lld",2*f[n]%p);
    }

    2.有点难想的

    三个性质:1.先下降数列等于先上升数列

        2.具有对称性即把数列反向仍然合法

        3.不好看出来的:在一个波动数列中,若两个 i 与 i+1 不相邻,那么我们直接交换这两个数字就可以组成一个新的波动数列 例如52314->42315

    设$f[i][j]$为$1-i$第一个数为$j$且先下降的方案数,答案为$sum_{j=1}^{n} f[n][j]$

    由性质三可知如果$j$与$j-1$不相邻时以$j$开头和以$j-1$开头的方案数一样,$j$和$j-1$不相邻的情况,先赋值$f[i][j]=f[i][j-1]$

    接下来处理$j$和$j-1$相邻的情况,这样确定了后面那个是$j-1$,只要知道$j-1$开头的先上升序列数量即可,注意这里也相当于把数字离散化了,只是相对大小所以直接加没影响,求先上升序列数量需要用性质1取反一下$f[i][j]+=f[i-1][(i-1+1)-(j-1)]$

    综上$f[i][j]=f[i-1][j-1]+f[i-1][i-j+1]$

        

  • 相关阅读:
    「CF1051F」The Shortest Statement
    「CF911F」Tree Destruction
    「HNOI/AHOI2018」游戏
    「CF859E」Desk Disorder
    「CF858F」 Wizard's Tour
    「CF894E」 Ralph and Mushrooms
    「NOIP2018」赛道修建
    「POI2010」Bridges
    常见神经网络
    数字图像处理笔记2.22
  • 原文地址:https://www.cnblogs.com/superminivan/p/11510664.html
Copyright © 2011-2022 走看看