[超级码力在线编程大赛初赛(二)] 4.小栖的金字塔 施罗德数(超级卡特兰数)

题目链接:小栖的金字塔
题意

题目图片
小栖可以在不同点间移动,假设小栖现在在 ( x 1 , y 1 ) {(x_1,y_1)} (x1,y1),他能够移动到的下一个点 ( x 2 , y 2 ) {(x_2,y_2)} (x2,y2)满足 ( x 2 > = x 1 & & y 2 > = y 1 ) {(x_2>=x_1 \&\& y_2>=y_1)} x2>=x1&&y2>=y1。现在小栖呆在 ( k , k ) {(k,k)} (k,k)处,由于我们不能确定小栖现在在哪儿,所以你需要求出所有点到达的方案数的和。

题解

这道题你要是对卡特兰数稍微有点涉猎就能做。
直接推的话稍微有点难度,在比赛里,感觉我推出来的可能性不大。

本题小栖可以走三个点 ( x 1 + 1 , y 1 ) , ( x 1 , y 1 + 1 ) , ( x 1 + 1 , y 1 + 1 ) {(x_1+1,y_1),(x_1,y_1+1),(x_1+1,y_1+1)} (x1+1,y1)(x1,y1+1)(x1+1,y1+1),这和施罗德数(超级卡特兰数)的例子一模一样,由于整个网格为三角形,最右边为 ( k , k ) {(k,k)} (k,k),相当于代替了“y=x这条直线”,这样一来,我们很容易得出答案就是施罗德数(超级卡特兰数)。

施罗德数(超级卡特兰数)的递推公式:
( n + 1 ) ∗ S n = ( 6 n − 3 ) ∗ S n − 1 − ( n − 2 ) ∗ S n − 2 {(n+1)*S_n=(6n-3)*S_{n-1}-(n-2)*S_{n-2}} (n+1)Sn=(6n3)Sn1(n2)Sn2 S 0 = 1 , S 1 = 1 {S_0=1,S_1=1} S0=1,S1=1
由于取模,所以求 s n {s_n} sn时,两边同乘以(n+1)的逆元即可。

注意这里递推出来的序列 S n {S_n} Sn并不直接是施罗德数(超级卡特兰数),而是除了第一项不变,剩下的都是施罗德数(超级卡特兰数)的一半,所以最后记得乘2哦。

注意题目里n≠k.size(),一开始我一直按n来写导致段错误,最后改为k.size()才过

代码
typedef long long ll;
ll mod=1e9+7;

class Solution {
public:
	/**
	 * @param n: The number of pyramid levels n
	 * @param k: Possible coordinates k
	 * @return: Find the sum of the number of plans
	 */
	 ll f[10000010];
	ll qpow(ll a, ll b)
	{
		ll ans=1;
		while(b)
		{
			if(b&1) ans=ans*a%mod;
			a=a*a%mod;
			b>>=1;
		}
		return (ans+mod)%mod;
	}
	int pyramid(int n, vector<int> &k) {
		// write your code here
		f[1]=f[0]=1;
		for(int i=2;i<=n;i++)
		{
			f[i]=((6*i-3)*f[i-1]%mod-(i-2)*f[i-2]%mod+mod)%mod*qpow(i+1,mod-2)%mod;	
		}
		ll ans=0;
		for(int i=0;i<k.size();i++) 
		{
			if(n==k[i]) ans=(ans+f[n-k[i]])%mod;
			else ans=(ans+f[n-k[i]]*2%mod)%mod;
		}
		return ans;
	}
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值