• bzoj1925 [Sdoi2010] 地精部落


    题目描述

    传说很久以前,大地上居住着一种神秘的生物:地精。

    地精喜欢住在连绵不绝的山脉中。具体地说,一座长度为N的山脉H可分为从左到右的N段,每段有一个独一无二的高度Hi,其中Hi是1到N之间的正整数。

    如果一段山脉比所有与它相邻的山脉都高,则这段山脉是一个山峰。位于边缘的山脉只有一段相邻的山脉,其他都有两段(即左边和右边)。

    类似地,如果一段山脉比所有它相邻的山脉都低,则这段山脉是一个山谷。

    地精们有一个共同的爱好——饮酒,酒馆可以设立在山谷之中。地精的酒馆不论白天黑夜总是人声鼎沸,地精美酒的香味可以飘到方圆数里的地方。

    地精还是一种非常警觉的生物,他们在每座山峰上都可以设立瞭望台,并轮流担当瞭望工作,以确保在第一时间得知外敌的入侵。

    地精们希望这N段山脉每段都可以修建瞭望台或酒馆的其中之一,只有满足这个条件的整座山脉才可能有地精居住。

    现在你希望知道,长度为N的可能有地精居住的山脉有多少种。两座山脉A和B不同当且仅当存在一个i,使得Ai≠Bi。由于这个数目可能很大,你只对它除以P的余数感兴趣。

    输入输出格式

    输入格式:

    输入文件goblin.in仅含一行,两个正整数N, P。

    输出格式:

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

    输入输出样例

    输入样例#1: 
    4 7
    输出样例#1: 
    3

    说明

    【数据规模和约定】

    对于20%的数据,满足N≤10;

    对于40%的数据,满足N≤18;

    对于70%的数据,满足N≤550;

    对于100%的数据,满足3≤N≤4200,P≤1e9。

    题解

    好题……思维难度省选,代码难度普及-……

    大佬真厉害

    首先先弄清楚三个性质

    $$性质一:在一个波动序列中,如果数字i与i+1不相邻,那么交换i与i+1,得到的仍然是一个波动序列$$

    $$证明:若i为山峰,交换后i+1必然也为山峰。同理,若i+1为山谷,交换后i也必为山谷$$

    $$若i为山谷,因为i+1与i不相邻,所以i两边的高度都大于i+1,所以交换后i+1小于其两边,仍为山谷。同理,若i+1为山峰,交换后i也为山峰$$

     

    $$性质二:把波动序列中的每一个数i换成n+1-i,得到的仍是一个波动序列$$

    $$证明:原来是山峰的地方变为山谷,原来是山谷的地方便为山峰,仍是波动序列$$

     

    $$性质三:波动序列具有对称性,即将一个波动序列翻转后仍是波动序列$$

    $$证明:正确性显然$$

    于是就可以考虑如何写状态转移方程了。设$f[i][j]$表示选了$1$到$i$的数,$j$为第一个数,且$j$为山峰

    很明显答案为$sum_{i=1}^n f[n][i]$

    如何转移?

    先给出方程:$f[i][j]=f[i][j-1]+f[i-1][i-j+1]$

    首先,因为由性质一可知,当$j$与$j-1$不相邻时,$j$作为第一个数和$j-1$作为第一个数的方案数相同

    又因为$j-1$为山峰,且是第一个数,故$j$与$j-1$必定不相邻

    然后,我们来考虑$j$和$j-1$相邻的情况

    选了$j$为山峰,则第二个数$j-1$必然为山谷,后面的数为$[1,j-1]$和$[j+1,i]$

    问题转变为求$i-1$个数,$j-1$为开头的山谷的方案数

    由性质二可得,$j-1$作为山峰和山谷的方案数相同

    又因为山峰和山谷是相对位置关系,所以将$[j+1,i]$区间每一个数减一,对方案无影响

    于是我们加上$f[i-1][(i-1+1)-(j-1)]$即可

    解决了

    ps:代码难度和思维难度真心不成正比……

     1 //minamoto
     2 #include<bits/stdc++.h>
     3 #define N 5005
     4 #define inf 0x3f3f3f3f
     5 using namespace std;
     6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<15,stdin),p1==p2)?EOF:*p1++)
     7 char buf[1<<15],*p1=buf,*p2=buf;
     8 inline int read(){
     9     #define num ch-'0'
    10     char ch;bool flag=0;int res;
    11     while(!isdigit(ch=getc()))
    12     (ch=='-')&&(flag=true);
    13     for(res=num;isdigit(ch=getc());res=res*10+num);
    14     (flag)&&(res=-res);
    15     #undef num
    16     return res;
    17 }
    18 int n,mod,f[2][N];
    19 int main(){
    20     //freopen("testdata.in","r",stdin);
    21     n=read(),mod=read();
    22     f[0][2]=1;
    23     for(int i=3;i<=n;++i)
    24     for(int j=2;j<=i;++j)
    25     f[i&1][j]=(f[i&1][j-1]+f[i-1&1][i-j+1])%mod;
    26     int ans=0;
    27     for(int j=2;j<=n;++j)
    28     ans=(ans+f[n&1][j])%mod;
    29     printf("%d
    ",(ans<<1)%mod);
    30     return 0;
    31 }
  • 相关阅读:
    win2003服务器网站和数据库的二周自动备份
    尝试jquery插件的开发
    Git 代码版本管理
    实验三、UML 建模工具的安装与使用
    实验五 单元检测
     实验四 代码评审
    实验二 结队编程(第二阶段)
    结队编程
    第一次实验
    用live writer发布文章文章中含时产生的bug
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9372182.html
Copyright © 2020-2023  润新知