• [BZOJ] 地精部落


    问题描述

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

    输入格式

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

    输出格式

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

    样例输入输出

    Input
    4 7
    Output
    3

    数据范围

    对于 20%的数据,满足 N≤10;
    对于 40%的数据,满足 N≤18;
    对于 70%的数据,满足 N≤550;
    对于 100%的数据,满足 3≤N≤4200,P≤10 9

    解析

    题意即为求用n个数构成波动序列的方案数。

    考虑波动序列有如下性质:

    • 在一个波动数列中,若两个 i 与 i+1 不相邻,那么我们直接交换这两个数字就可以组成一个新的波动数列;
    • 把波动数列中的每个数字Ai 变成 (N+1)-Ai 会得到另一个波动数列,且新数列的山峰与山谷情况相反;
    • 波动序列有对称性。 比如:1 4 2 5 3 和 3 5 2 1 4

    那么,根据这些性质,我们可以设如下状态:(f[i][j])表示用了1~i的数,第一项为j的方案数。由于性质2,第一项为山峰对称一下就可以得到第一项为山谷的方案,因此不妨设j为山峰,最后乘2即可。

    下面讨论转移。由性质1,当j与j-1不相邻时,(f[i][j]=f[i][j-1])。当j-1与j相邻时,j-1只能为山谷且位于第2位。后面的取值范围是([1,j-1])([j+1,i])。同理,第一位为山谷的方案数可以通过性质3由山峰的方案推出,接下来只需要处理值域有空缺的问题。其实我们关心的只是相对的高矮,将区间([j+1,i])整体减一并不影响答案。因此,相当于求用i-1个数0其中第j-1为第一位且为山谷的方案,为(f[i-1][(i-1+1)-(j-1)]=f[i-1][i-j+1])。状态转移方程如下:

    [f[i][j]=f[i][j-1]+f[i-1][i-j+1] ]

    最后答案为

    [ans=sum_{i=1}^{n}f[n][i] ]

    注意用滚动数组优化空间。初始值因为1不可能作为山峰,要从2开始。

    代码

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #define N 4202
    using namespace std;
    int n,p,i,j,f[2][N],x;
    int main()
    {
    	cin>>n>>p;
    	f[0][2]=1;
    	for(i=3;i<=n;i++){
    		for(j=2;j<=i;j++) f[x^1][j]=(f[x^1][j-1]+f[x][i-j+1])%p;
    		x^=1;
    	}
    	int ans=0;
    	for(i=2;i<=n;i++) ans=(ans+f[x][i])%p;
    	cout<<ans*2%p<<endl;
    	return 0;
    }
    
  • 相关阅读:
    HDU5418.Victor and World(状压DP)
    POJ2686 Traveling by Stagecoach(状压DP)
    POJ3254Corn Fields(状压DP)
    HDU5407.CRB and Candies(数论)
    CodeForces 352D. Jeff and Furik
    CodeForces 352C. Jeff and Rounding(贪心)
    LightOj 1282 Leading and Trailing
    Ural 1057. Amount of Degrees(数位DP)
    HDU 2089 不要62 (数位DP)
    HDU5366 The mook jong (DP)
  • 原文地址:https://www.cnblogs.com/LSlzf/p/11415328.html
Copyright © 2020-2023  润新知