BUPT Summer Journey #test2 C

时间限制 1000 ms 内存限制 65536 KB

题目描述

现有一段横向长度为N的山脉,其中每段有一个独一无二的高度Hi(1到N之间的正整数)。现在你想知道对于长度为N的山脉,可能有这样的山脉多少种。这样的山脉是:某个位置要么比两边的高度都低,要么比两边的高度都高。两座山脉 A和 B 不同当且仅当存在一个 i,使得 Ai≠Bi。由于这个数目可能很大,你只对它除以 P 的余数感兴趣。

输入格式

输入以EOF为结束,每组仅含一行,两个正整数 N, P。 3≤N≤4200,P≤10^9

输出格式

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

输入样例

4 7

输出样例

3
说明:共有 10 种可能的山脉,它们是:
1324    1423    2143    2314    2413
3142    3241    3412    4132    4231 
思路:首先可以先打表找规律,然后发现前几项是1,2,4,10,22,32,122,544,2770,15872,101042,707584不难看出。它的增长率十分迅速。所以一定是和阶乘有关系的。其次,不难发现只有可能有/\/\/\/和\/\/\/\这两种情况,且不难发现两种情况是相等的。但考试的时候我和彦志两个人前面是一样的,到后来他得出递推公式后就直接AC了。我想之所以会这样,是因为我递推的时候没有化解题目中的因素,一个是单双峰的问题,一个是用最大的来缩小问题。其实只需要把每次最大的加在偶数个位置上,得到单峰的数,又因为双峰/2的时候难求出它的逆,所以化为单峰问题,统计奇数个位置的点。设d[i]为第i座山峰单峰的个数,把i放到偶数个位置递推,即为d[i]=c(i-1,0)*d[i-1]+c(i-1,2)d[2]d[i-1-2]+...最后的答案即为d[n]*2%P;还有就是数组只能开int,开long long会爆内存,因为有可能过程会超过这个值,我是过程强制转化(long long)模后存在int内。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
using namespace std;
int n,p;
int c[4205][4205];
int g[4205];

int main()
{

    while(scanf("%d%d",&n,&p)==2)
    {
        for(int i=1;i<=n;i++)c[i][0]=1;c[1][1]=1;
        for(int i=2;i<=n;i++)
            for(int j=1;j<=i;j++)c[i][j]=(c[i-1][j-1]%p+c[i-1][j]%p)%p;
        g[0]=1%p;
        g[1]=1%p;
        g[2]=1%p;
        g[3]=2%p;
        for(int i=4;i<=n;i++)
            for(int j=0;j<=i;j+=2)
            g[i]=(g[i]+(long long)c[i-1][j]%p*(long long)g[j]%p*(long long)g[i-1-j]%p)%p;
        g[n]=g[n]*2%p;
        printf("%d\n",g[n]);
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值