题解 题

传送门

是个\(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;
}
posted @ 2021-06-08 07:49  Administrator-09  阅读(23)  评论(0编辑  收藏  举报