组合数学好题!
首先考虑题目要求,在一个数
x
x
x后面填的数可以是
x
,
x
−
1
,
x
+
1
x,x-1,x+1
x,x−1,x+1,把数列看做网格图,把
+
1
+1
+1看做右上走一步,
−
1
-1
−1右下,
0
0
0往右,问题变成了从
(
0
,
0
)
−
>
(
n
−
1
,
m
)
(0,0)->(n-1,m)
(0,0)−>(n−1,m)不穿过
x
=
0
x=0
x=0的方案数,根据套路,可以用总
−
-
−穿过的,穿过的就可以用
(
0
,
0
)
(0,0)
(0,0)关于
x
=
−
1
x=-1
x=−1对称一下,就是
(
0
,
−
2
)
−
>
(
n
−
1
,
m
)
(0,-2)->(n-1,m)
(0,−2)−>(n−1,m)的方案数
首先枚举往右走的步数
i
i
i,再枚举最后走到的那个
m
m
m,就可以这样算:
a
n
s
=
∑
i
=
0
n
C
n
−
1
i
×
∑
j
=
(
n
−
i
−
1
)
&
1
,
j
&
1
=
(
n
−
i
−
1
)
&
1
n
−
i
−
1
C
n
−
i
−
1
n
−
i
+
j
−
1
2
−
C
n
−
i
−
1
n
−
i
+
j
+
1
2
ans=\sum_{i=0}^n C_{n-1}^i\times \sum_{j=(n-i-1)\&1,j\&1=(n-i-1)\&1}^{n-i-1}C_{n-i-1}^{\frac{n-i+j-1}{2}}-C_{n-i-1}^{\frac{n-i+j+1}{2}}
ans=i=0∑nCn−1i×j=(n−i−1)&1,j&1=(n−i−1)&1∑n−i−1Cn−i−12n−i+j−1−Cn−i−12n−i+j+1
观察式子,因为每次相当于给
j
+
=
2
j+=2
j+=2,所以除二就能消掉,就变成了杨辉三角中一行的一半,然后前面后面相差一,所以中间都抵消了,最后就变成:
a
n
s
=
∑
i
=
0
n
C
n
−
i
i
×
{
C
n
−
i
−
1
n
−
i
2
(
n
−
i
−
1
)
&
1
C
n
−
i
−
1
n
−
i
−
1
2
!
(
n
−
i
−
1
)
&
1
ans=\sum_{i=0}^nC_{n-i}^i\times \begin{cases}C_{n-i-1}^{\frac{n-i}{2}}&(n-i-1)\&1\\C_{n-i-1}^{\frac{n-i-1}{2}}&!(n-i-1)\&1\end{cases}
ans=i=0∑nCn−ii×{Cn−i−12n−iCn−i−12n−i−1(n−i−1)&1!(n−i−1)&1
放上我并列第一快 的代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 1000005
#define LL long long
using namespace std;
int n,fac[maxn],inv[maxn];
const int mod=1e9+7;
LL ans;
inline int qpow(int x,int k){
int ret=1;
while(k){
if(k&1) ret=1LL*ret*x%mod;
x=1LL*x*x%mod; k>>=1;
} return ret;
}
inline int C(int n,int m){ return 1LL*fac[n]*inv[m]%mod*inv[n-m]%mod;}
int main(){
scanf("%d",&n); fac[0]=1;
for(int i=1;i<=n;i++) fac[i]=1LL*fac[i-1]*i%mod;
inv[n]=qpow(fac[n],mod-2);
for(int i=n;i;i--) inv[i-1]=1LL*inv[i]*i%mod;
for(int i=0;i<=n;i++){
if((n-i-1)&1) (ans+=1LL*C(n-1,i)*C(n-i-1,(n-i)>>1)%mod)%=mod;
else (ans+=1LL*C(n-1,i)*C(n-i-1,(n-i-1)>>1)%mod)%=mod;
}
printf("%lld\n",ans);
return 0;
}