zoukankan      html  css  js  c++  java
  • bzoj 1925

    一道略有难度的dp

    设状态$dp[i][j]$表示长度为$i$,开头高度为$j$且为山峰的方案数

    考虑到一个序列是对称的,所以总方案数即为$2*sum_{i=2}^{n}dp[n][i]$

    这样我们只需考虑转移即可

    首先,我们发现,如果两个数$i$与$i+1$不相邻,那么交换这两个数之后方案数不变

    这个...感性理解一下,如果两个数不相邻,若$i$在原位置是山峰,换成$i+1$后肯定仍然是山峰,而如果$i$在原位置是山谷,那么换成$i+1$后由于$i+1$并不在$i$的左右,因此换成$i+1$后肯定仍为山谷

    剩下的同理可证

    因此第一个方向就是:假设$j$与$j-1$不相邻,那么转移就是$dp[i][j]=dp[i][j-1]$(即原来$j-1$在山峰,然后交换$j$与$j-1$,方案数不变)

    那么如果$j$与$j-1$相邻呢?

    那么需要第二个性质:如果一个序列{$a_{i}$}是波动序列,那么序列{$(n+1)-a_{i}$}也是波动序列,且波峰波谷恰好相反

    那么如果$j$与$j-1$相邻,$j$在首位为波峰,那么$j-1$必然在第二位为波谷,那么我们只需求出$j-1$为波谷的方案即可

    再根据第二条性质,我们可以将所有以$j-1$开头为波谷的序列每一位用$i-1+1$去减,那么就会变成以$i-j+1$为开头波峰的方案数

    因此总转移方程即为$dp[i][j]=dp[i][j-1]+dp[i-1][i-j+1]$

    滚动数组优化一下即可

    #include <cstdio>
    #define ll long long
    ll dp[2][4505];
    ll n,p;
    int main()
    {
        scanf("%lld%lld",&n,&p);
        dp[0][2]=1;
        for(int i=3;i<=n;i++)for(int j=2;j<=i;j++)dp[i&1][j]=(dp[i&1][j-1]+dp[(i-1)&1][i-j+1])%p;
        ll ans=0;
        for(int i=2;i<=n;i++)ans=(ans+dp[n&1][i])%p;
        printf("%lld
    ",ans*2%p);
        return 0;
    }
  • 相关阅读:
    量化平台的发展转
    jmeter全面总结8jmeter实战
    月见笔谈【一】——关于悲剧
    为什么要不断接触和学习新技术之我见
    WPF后台动态调用样式文件
    WPF后台动态添加TabItem并设置样式
    SQL查询SQLSERVER数据库中的临时表结构脚本
    防抖功能的实现
    项目中自定义进度条的实现
    vue3 请求响应拦截
  • 原文地址:https://www.cnblogs.com/zhangleo/p/10969959.html
Copyright © 2011-2022 走看看