首页 > 其他 > 详细

[Sdoi2010]地精部落

时间:2019-07-05 14:50:41      阅读:114      评论:0      收藏:0      [点我收藏+]

题面:

题目描述

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

输入格式

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

输出格式

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

样例

样例输入

4 7

样例输出

3

数据范围与提示

技术分享图片
对于 20%的数据,满足 N≤10;
对于 40%的数据,满足 N≤18;
对于 70%的数据,满足 N≤550;
对于 100%的数据,满足 3≤N≤4200,P≤10910^910?9??

分析:

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

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

  拿过题面看到数据范围首先想到状压(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\n",res%P);
22 }
70%

  对,还是WA了,能看到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\n",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\n",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\n",(qsum[past][0][N-1]+qsum[past][1][2])%P);
}
100%

 

 

[Sdoi2010]地精部落

原文:https://www.cnblogs.com/2018hzoicyf/p/11137164.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!