51nod 1556 计算&&卡特兰数的扩展,HV格路径

本文详细解析了51nod1556计算题,探讨了如何利用组合数学中的卡特兰数概念解决特定序列的问题。通过数学推导得出公式,并提供了解决任意前缀和不小于0的序列数量的算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

51nod 1556 计算

有一个1*n的矩阵 固定第一个数为1 其他填正整数
且相邻数的差不能超过1 求方案数%(109+7)的结果

1*n的矩阵。前后的绝对值差不超过1.
设 第i个数大小为

Ai

则有

AiAi1=0 , 1 ,1

那么。前后项做差,我们会得到一个序列。
这个序列仅仅由1,0,-1组成
(组合数学里面讲卡特兰数时是我第一次见+1,-1,组成序列的许多性质)
原问题等价于1,-1,0,组成的序列,任意前缀和不小于1的序列数量。
设 有 n个 +1 ,m个 1组成的序列{ai}
其中n>=m
则一个合法序列为 :任意前缀和不小于0的序列。
即:

i=1kai0,  kn+m

则合法序列的数量为:

(n+mm)(n+mm1)

上面的公式可以用于计算出来第n个卡特兰数
————————不喜欢看计算的可以跳过——————————–

不特别说明的话 ,下面都有

n>=m

细心观察,上面公式左边:

(n+mm)

相当于,所有排列数量。(多重集合的排列。。。
其实 。右边:

(n+mm1)

相当于不合法序列的数量;
应用减法原理。便有这个公式。
对于第一部分。 n个+1与m个-1 组成的序列的所有排列情况数
我们只需要确定其中+1或者-1的位置,而另一种数字的位置也就随之确定了。

我们先让-1选择属于它的一些位置。-1选择位置 的 方案数量为:

(n+mm)

公式的第二部分,不合法序列的数量:
为了便于理解。
我们来发掘一些不合法序列必有的特征:
首先。既然序列不合法。那么必然存在在某个位置 k,有:

i=1kai<0
最小的那个 k 很重要
虽然不能描述整个序列的情况。
但它概述了一类这样不合法的序列。
即:
k01k
注意:是第一次。
那么对于序列

a1,a2,....,ak

这部分很特别。 我们说是特征。
通过把这k个数取反。我们得到了一个由

n+1+1m11

组成的序列。对于这个序列,有:
k02k
这也就是说。n+1个+1,m-1个-1组成的序列,都可以通过取反特征2部分。
来变换出一个由 n个+1,m个-1组成的不合法序列。
同时 n个+1,m个-1组成的序列,也可以通过取反特征1部分。
来得到一个由n+1个+1,m-1个-1组成的序列。
综上,n个+1,m个-1组成的不合法序列的数量为,即为,n+1个+1,m-1个-1组成序列的数量:
(n+mm1)

所以:n个+1,m个-1,n>=m组成任意前缀和不小于0的序列数量为:

(n+mm)(n+mm1)
———————————–计算结束————————————————

回到原问题:

对于 长度为 x的序列,只使用 ±1,组成任意前缀和不小于0
的序列数量为 记为:
S[x]
则有:

S[x]=i=0x2[(xi)(xi1)]=(xx2)

因为第一个元素为1,在不考虑第一个元素,原问题等价于,任意前缀和不小于0.
序列的基本元素除了x±1之外,还有 0.
所以,枚举不同的x并添加 (n1x)个0,来得到答案。
这里之所以是n-1-x个0,是因为第一个位置固定为1,序列长度变为n-1,原问题变形为前缀和不小与0

综上有:
answer=x=0n1(S[x](n1n1x))=x=0n1((xx2)(n1x))

其中:
(00)=1

下面是代码:

#include <algorithm>
#include <string.h>
#include <stdio.h>
#define MAXN 1000005
using namespace std;
typedef long long LL;
const LL P=1e9+7;
LL Ivn[MAXN]={0,1};
LL S[MAXN];

int main ()
{
    int n,sz=1;
    scanf("%d",&n);
    if(n==1)
    {
        printf("1\n");
        return 0;
    }
    sz+=n;
    for(int i=2;i<sz;i++)   Ivn[i]=P-P/i*Ivn[P%i]%P;
    S[0]=1;
    S[1]=1;
    S[2]=2;
    for(int i=3,j=4; i<sz;i+=2,j+=2)
    {
        S[i]=S[i-2];
        S[i]*=i;    S[i]%=P;
        S[i]*=i-1;  S[i]%=P;
        S[i]*=Ivn[((i-2)>>1)+1]; S[i]%=P;
        S[i]*=Ivn[((i-2)>>1)+2]; S[i]%=P;
        S[j]=S[j-2];
        S[j]*=j-1;  S[j]%=P;
        S[j]*=j;    S[j]%=P;
        S[j]*=Ivn[((j-2)>>1)+1]; S[j]%=P;
        S[j]*=Ivn[((j-2)>>1)+1]; S[j]%=P;
    }
    LL ans=0,C=1;
    for(int i=0;i<n;i++)
    {
        ans+=C*S[i]%P;
        if(ans>=P)ans-=P;
        C*=n-i-1;
        C%=P;
        C*=Ivn[i+1];
        C%=P;
    }
    printf("%lld\n",ans);
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值