• [Sdoi2010]地精部落


    题面:

    题目描述

    传说很久以前,大地上居住着一种神秘的生物:地精。 地精喜欢住在连绵不绝的山脉中。具体地说,一座长度为 N 的山脉 H可分 为从左到右的 N 段,每段有一个独一无二的高度 Hi,其中Hi是1到N 之间的正 整数。 如果一段山脉比所有与它相邻的山脉都高,则这段山脉是一个山峰。位于边 缘的山脉只有一段相邻的山脉,其他都有两段(即左边和右边)。 类似地,如果一段山脉比所有它相邻的山脉都低,则这段山脉是一个山谷。 地精们有一个共同的爱好——饮酒,酒馆可以设立在山谷之中。地精的酒馆 不论白天黑夜总是人声鼎沸,地精美酒的香味可以飘到方圆数里的地方。 地精还是一种非常警觉的生物,他们在每座山峰上都可以设立瞭望台,并轮 流担当瞭望工作,以确保在第一时间得知外敌的入侵。 地精们希望这N 段山脉每段都可以修建瞭望台或酒馆的其中之一,只有满足 这个条件的整座山脉才可能有地精居住。 现在你希望知道,长度为N 的可能有地精居住的山脉有多少种。两座山脉A 和B不同当且仅当存在一个 i,使得 Ai≠Bi。由于这个数目可能很大,你只对它 除以P的余数感兴趣。

    输入格式

    仅含一行,两个正整数 N, P。

    输出格式

    仅含一行,一个非负整数,表示你所求的答案对P取余 之后的结果。

    样例

    样例输入

    4 7

    样例输出

    3

    数据范围与提示

    image
    对于 20%的数据,满足 N≤10;
    对于 40%的数据,满足 N≤18;
    对于 70%的数据,满足 N≤550;
    对于 100%的数据,满足 3≤N≤4200,P≤10910^9109​​

    分析:

      首先,强烈谴责将此题放到数学中

      主流算法貌似是一个什么波动序列(本人不会)

      拿过题面看到数据范围首先想到状压(20%),后来在whs大神的启发下,发现用状压保存山脉的状态没什么卵用。这里有个比较重要的性质:及维护一个固定长度的山脉,只要保证山峰高度不同,那么方案数是固定的,与山峰具体高度无关(有点像Perm排列计数)。所以只要枚举山脉长度,将新山峰插入转移即可。

      $dp[k][len][i]$为考虑到的山脉长度为$len$,山脉末尾山峰的相对高度排名为i,是山峰还是谷地的方案数。

      $dp[k][len][i]=∑dp[k $^$ 1][len-1][s]$

      如果为山峰,$s$属于$(1,i-1)$,因为在原山脉排名为$s$,在新山脉排名也为s

      为谷地时,$s$属于$(i,len-1)$,在新山脉中所要的其实是$(i+1,len)$,但除去了$i$,在原山脉实际为$(i,len-1)$

     1 #include<iostream>
     2 #include<cstdio>
     3 #define MAXN 4210
     4 using namespace std;
     5 int N;
     6 int P;
     7 int dp[2][MAXN][MAXN];
     8 int res;
     9 int main(){
    10     scanf("%d%d",&N,&P);
    11     dp[0][1][1]=dp[1][1][1]=1;
    12     for(int len=2;len<=N;++len)
    13         for(int i=1;i<=len;++i){
    14             for(int s=i;s<len;++s)
    15                 dp[0][len][i]=(dp[0][len][i]+dp[1][len-1][s])%P;
    16             for(int s=i-1;s>=1;--s)
    17                 dp[1][len][i]=(dp[1][len][i]+dp[0][len-1][s])%P;
    18         }
    19     for(int i=1;i<=N;++i)
    20         res=(res+dp[0][N][i]+dp[1][N][i])%P;
    21     printf("%d
    ",res%P);
    22 }
    70%

      对,T了,能看到4200×4200,时间长空间大,考虑滚动数组和前缀和即可

    最后

    #include<iostream>
    #include<cstdio>
    #define MAXN 4210
    using namespace std;
    int N;
    int P;
    int dp[2][2][MAXN];
    int res;
    int qsum[2][2][MAXN];
    int main(){
        scanf("%d%d",&N,&P);
        int now=0,past=1;
        dp[past][0][1]=dp[past][1][1]=1;
        qsum[past][0][1]=qsum[past][1][1]=1;
        for(int len=2;len<=N;++len){
            for(int i=1;i<=len;++i){
                dp[now][0][i]=qsum[past][1][i];
    //            printf("%d 0 %d %d
    ",len,i,dp[now][0][i]);
                qsum[now][0][i]=(qsum[now][0][i-1]+dp[now][0][i])%P;
            }
            for(int i=len;i>=1;--i){
                dp[now][1][i]=qsum[past][0][i-1];
    //            printf("%d 1 %d %d
    ",len,i,dp[now][1][i]);
                qsum[now][1][i]=(qsum[now][1][i+1]+dp[now][1][i])%P;
            }
            now=past;past^=1;
        }
        printf("%d
    ",(qsum[past][0][N-1]+qsum[past][1][2])%P);
    }
    100%

     

     

  • 相关阅读:
    c#类的小小理解
    sql语句:保留要害字的问题.例如 size,text,user等
    c#2005做新闻发布系统心得
    asp 遇到过的问题集锦,附加asp语句添加数据库和生成表,asp命令更改指定文件的文件名,asp值传递的应用091116小结
    dropdownlist控件失去焦点的小应用和函数substr
    获得当前应用程序路径C#03
    模糊查询简单分析,得出sql语句
    20080905经典的DataReader对象解读+几种对数据库的操作的命令,20100111update read db example
    Servlet 容器的工作原理 ( 二 )
    手低眼高 初学者学习Hibernate的方法
  • 原文地址:https://www.cnblogs.com/2018hzoicyf/p/11137164.html
Copyright © 2020-2023  润新知