题目链接:小栖的金字塔
题意
小栖可以在不同点间移动,假设小栖现在在
(
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=(6n−3)∗Sn−1−(n−2)∗Sn−2 (
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;
}
};