地精部落

来源:互联网 发布:栈实现链表反转java 编辑:程序博客网 时间:2024/05/16 18:36
题目描述 Description

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

输入描述 Input Description

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

输出描述 Output Description

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

样例输入 Sample Input

4 7

样例输出 Sample Output

3

数据范围及提示 Data Size & Hint

共有10 种可能的山脉,它们是: 
1324 1423 2143 2314 2413 
 
3142 3241 3412 4132 4231   
【数据规模和约定】 
对于 20%的数据,满足 N≤10; 
对于 40%的数据,满足 N≤18; 
对于 70%的数据,满足 N≤550; 
对于 100%的数据,满足 3≤N≤4200,P≤109   

评价:这道题是我看了题解以后才做出来的,真是一道神题,但是写题解的大神都不愿解释得太详细,所以我想了很久才想明白。。。看了题解以后真的觉得很像数的划分、约瑟夫问题还有国王游戏,代码出奇地简洁,但是思维量相当地高。
 题解:
三个引理:
 
①在n->n-1的转化过程中,我们删除了一个点后,我们可以将n-1个点视为仍是1~n-1的排列。
 
②在若排列Pn为一个合法抖动子序列,则交换i∈[1,n)与i+1,必能得到另一个抖动子序列。
 
③抖动序列的对称性,若存在第一段上升的长度为n的抖动子序列,则以n+1-x代x必能得到一个第一段下降的长度为n的抖动子序列。 

设f[i][j]为长度为i的,以j开头的,第一段下降的抖动子序列的个数,则循题意可得2*f[n+1][n+1]即为答案。

考虑转移:

①若j的下一个是j-1,则需要一个长度为n-1的,以j-1开头的上升子序列;

再分两种情况:

若j==n,则j-1为i-1中正数第一个数,所以可以转移到f[i][1];

若j<n,则j-1为i-1中正数第i-1-(j-1)+1-1个数,所以可转移到f[i-1][j-i].

我们根据状态设定,显然有f[i][0]=f[i][1]=0.

∴f[i][j]->f[i-1][j-i].

②若j的下一个不是j-1,则对于任意一个以j-1开头的下降子序列,均可以通过交换j-1和j+1得到。

∴f[i][j]->f[i][j-1]

综,f[i][j]=f[i-1][j-i]+f[i][j-1].

减少代码量?一个技巧:

改变状态,令f[i][j]=f[i+1][j+1],则初始状态变更为f[1][1]=1,i∈[1,n],j∈[1,n].
ps:这个题是2010年山东省赛第一轮第二试的第一题。。竟然如此蛋疼。。。。顿时感觉明年的省赛会很呵呵。。。 

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include<iostream>  
  2. using namespace std;  
  3. #include<cstdio>  
  4. #include<cmath>  
  5. #include<algorithm>  
  6. #include<cstring>  
  7. int f[2][10001];  
  8. int main(){  
  9.     int n,p;  
  10.     bool tmp;  
  11.     scanf("%d%d",&n,&p);  
  12.     f[1][1]=1;  
  13.     for(int i=2;i<=n;++i){  
  14.         tmp=i&1;  
  15.         for(int j=1;j<=i;++j)  
  16.             f[tmp][j]=(f[!tmp][i-j+1]+f[tmp][j-1])%p;  
  17.     }  
  18.     printf("%d",(f[tmp][n]<<1)%p);  
  19.  
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 两个月宝宝有火怎么办 2岁宝宝起眼屎怎么办 一周岁的宝宝皮肤过敏怎么办 两岁宝宝脾气倔不听话怎么办 22个月宝宝打人怎么办 两岁宝宝会打人怎么办 3岁哭闹倔强不止怎么办 我儿子二十三岁不爱说话怎么办 2岁宝宝不听话脾气大怎么办 2岁宝宝调皮不听话怎么办 2岁的宝宝不听话怎么办 2岁宝宝总是不听话怎么办 2岁宝宝淘气不听话怎么办 两岁宝宝不听大人的话怎么办? 来月经奶量减少怎么办 月经来了奶少怎么办 来例假奶水少了怎么办 两岁宝宝吐口水怎么办 3岁宝宝不愿自己吃饭怎么办 婆家的人很烦人怎么办 三十了还没结婚怎么办 两岁宝贝断奶粉怎么办 宝宝断了母乳不吃奶粉怎么办 一岁宝宝不爱吃辅食怎么办 断奶后宝宝抗拒奶瓶怎么办 两岁宝宝断奶后不喝奶粉怎么办 两岁宝宝断奶不吃奶粉怎么办 宝宝断奶妈妈涨奶怎么办 三岁宝宝智商低怎么办 宝宝断奶晚上哭的厉害怎么办 2岁宝宝半夜喝奶粉怎么办 两岁宝宝不爱吃饭怎么办 快两岁的宝宝不爱吃饭怎么办 宝宝断奶后不愿意喝奶粉怎么办 宝宝断奶了不愿意喝奶怎么办? 宝宝断奶不愿意喝奶粉怎么办 宝宝断奶不愿意喝牛奶怎么办? 四个月宝宝断奶不吃奶粉怎么办 2岁不开口说话怎么办 八个月宝宝断奶不吃奶粉怎么办 宝宝断奶不喝奶粉怎么办 周岁