题解 题
是个\(Catalan\)数的模板题
首先\(Catalan\)数的通项公式为\(Cat(n) = \frac{C^n_{2n}}{n+1}\)
注意是\(n+1\) 我都打成\(n-1\)好几遍了
实际上数据很友好,像我这样不会\(Catalan\)数的选手靠组合数也骗了45pts
个人感觉这里\(Catalan\)数讲的不错
特别注意,t=3时可以任意走,所以只需要考虑不越过坐标轴,而「上下」和「左右」的顺序可以改变,每个顺序都对应了一组情况
所以 \(ans = \sum_{2|i} Cat(\frac{i}{2})\times Cat(\frac{n-i}{2})\times C^i_n\)
而t=2时很有意思,\(\leq 1000\)的数据范围明显在提醒我们跑dp 然而我考场上没看到这个数据范围
将整个行走以第一次回到原点为界限划分为两个部分
令\(dp[i]\)为从原点出发在坐标轴上走i步的方案数
则 \(dp[i] = \sum_{2|j}4\times Cat(\frac{j}{2}-1)\times dp[i-j]\)
这里乘4是指有4个方向可以走
至于\(\frac{j}{2}\)为什么要减一:
因为我要求的是第一次回到原点前向某一方向走法方案数
而\(Catalan\)数求的是不越过原点的走法方案数
所以我把这个不能越过的界限向这个方向移动一个位置
即向此方向可自由移动步数为\(\frac{j}{2}\).
Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
#define ld long double
#define usd unsigned
#define ull unsigned long long
//#define int long long
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
char buf[1<<21], *p1=buf, *p2=buf;
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n, k;
ll fac[N], inv[N], inv2[N];
//ll dp[2010][2010];
ll dp[2010];
const ll mod=1e9+7;
inline ll md(ll a) {return a>=mod?a-mod:a;}
inline ll C(ll n, ll k) {return fac[n]*inv2[k]%mod*inv2[n-k]%mod;}
inline ll cat(ll n) {return C(2*n, n)*inv[n+1]%mod;}
signed main()
{
#ifdef DEBUG
freopen("1.in", "r", stdin);
#endif
ll ans=0;
n=read(); k=read();
fac[0]=fac[1]=1; inv[0]=inv[1]=1; inv2[0]=inv2[1]=1;
for (int i=2; i<=n*2; ++i) fac[i]=fac[i-1]*i%mod; //, cout<<fac[i]<<' '; cout<<endl;
for (int i=2; i<=n*2; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod; //, cout<<inv[i]<<' '; cout<<endl;
for (int i=2; i<=n*2; ++i) inv2[i]=inv[i]*inv2[i-1]%mod;
if (n&1) {puts("0"); return 0;}
if (k==0) {
for (int i=0; i<=n; i+=2) ans = (ans+ fac[n]*inv2[i/2]%mod*inv2[i/2]%mod*inv2[(n-i)/2]%mod*inv2[(n-i)/2]%mod)%mod; //, cout<<fac[n]*inv[i]%mod*inv[i]%mod<<endl;
printf("%lld\n", ans);
}
else if (k==1) {
#if 0
dp[1][1]=dp[2][1]=1;
for (int i=1; i<=n; ++i) {
dp[i][i]=1;
for (int j=(i+1)>>1; j<i; ++j) {
if (j*2<i) continue;
dp[i][j] = md(dp[i-1][j]+dp[i-1][j-1]);
}
}
#endif
printf("%lld\n", cat(n/2));
}
else if (k==2) {
dp[0] = 1;
for (int i=0; i<=n; i+=2) {
for (int j=0; j<=i; j+=2) dp[i] = md(dp[i]+cat(j/2-1)*4*dp[i-j]%mod);
}
//cout<<dp[0]<<' '<<dp[2]<<' '<<dp[4]<<endl;
printf("%lld\n", dp[n]);
}
else {
for (int i=0; i<=n; i+=2) ans = md(ans+ cat(i/2)*cat((n-i)/2)%mod*C(n, i)%mod);
printf("%lld\n", ans);
}
return 0;
}