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


    地精部落 bzoj-1925 Sdoi-2010

    题目大意:给你一个数n和模数p,求1~n的排列中满足每一个数的旁边两个数,要么一个是边界,要么都比它大,要么都比它小(波浪排列个数)

    注释:$1le nle 4200$ , $1le ple 10^9$。

    想法:神题!这题标签给的是dp,但是一个没有动态性的dp应该叫递推吧qwq。先证几个引理:

    引理1:对于任意的一个波动序列,将其中的第i个数a[i]离散成坐标系中的一个点(i,a[i]),这样所构成的波动离散点集关于任意的一条平行于x轴的直线对称后的(i,a'[i]),a'序列仍是波动序列。

      证明:假设那条直线是y=b。那么对于任意的$iin [2,n-1]$,都有min(b-a[i-1],b-a[i+1])>b-a[i]或max(b-a[i-1],b-a[i+1])<b-a[i],反转之后,显然有max(a[i-1],a[i+1])<a[i]or min(a[i-1],a[i+1])>a[i],证毕。

    引理2:如果交换波动序列中两个位置不相邻但是单调性相邻的数(单调性相邻,就是说将原波动序列上的所有数按照权值排序后相邻的两个数),交换后的序列仍是波动序列,

      证明:显然。

    然后,我们设

      递推状态:dp[i][j],表示1~i的排列中,第一位为j且为山峰的方案数。

      转移:dp[i][j]=dp[i][j-1]+dp[i-1][i-j+1]。

    为什么呢?首先,我们对dp[i][j]的所有方案进行一个分划:由于j是第一位且为山峰,所以,j-1可以处在第二位。但是dp[i][j-1]中,j是不可能处在第二位的,所以,我们对于dp[i][j-1]中的每一种排列都将j和j-1交换。j-1是山峰交换后j自然也是山峰,由引理2可知交换后仍是波动序列。此时,我们处理好了j-1不在第二位的情况。如果j-1钦定在第二位呢?我们对于这样的i-1个数:1,2,...j-1,j+1,...,i。将它们所有的数都变成关于y=0对称后向上平移i个单位的数,即变成:i-1,i-2,...,i-j+1,i-j-1,...,0.然后,我们有:dp[i][i-j+1]是原序列从小到大排序,第i-j+1个数作为第一个数且为山峰的方案数。这样的方案数在将所有数都恢复到原来的样子,仍然是波动序列只不过第一个数是j-1且为山谷,将j放在j-1之前,恰满足题意。

    最后,附上丑陋的代码... ...

    #include<bits/stdc++.h>
    #define N 5010 
    using namespace std;
    int dp[2][N];
    int n,mod;
    int main()
    {
        scanf("%d%d",&n,&mod);
        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])%mod;
            }
        }
        int ans=0;
        for(int j=2;j<=n;j++)
        {
            ans=(ans+dp[n&1][j])%mod;
        }
        printf("%d",(ans<<1)%mod);
    }

    小结:对于波动序列,有一些小的引理或性质有待挖掘... ...

  • 相关阅读:
    JVM OOM处理
    Scala可变参数列表,命名参数和参数缺省
    Scala闭包
    Scala应用函数
    Scala函数字面量简化写法
    Scala函数字面量
    Scala中class和object的区别
    数据库的优化
    svn: warning: 'xxxxxx' is already under version control
    svn status 显示 ~xx
  • 原文地址:https://www.cnblogs.com/ShuraK/p/9032651.html
Copyright © 2020-2023  润新知