a

有一个三维坐标系,从起点\((0,0,0)\)开始走,每次只能向某个坐标轴的正方向走一步,其中有m个点不能走,问走到\((n,n,n)\)的方案数。\(n\leq 10^5\)\(m\leq 5000\)


有一个递推是:设f[n][m]表示走到编号为n的点,经过了至少m个点的方案数,那么答案就是\(\sum_{i=0}^m(-1)^if[(n,n,n)][i]\times{m\choose i}\)

考虑转移,\(f[n][m]=\sum_{i能到n}\quad f[i][m-1]\times{x_n+y_n+z_n-x_i-y_i-z_i\choose x_n-x_i}{y_n+z_n-y_i-z_i\choose y_n-y_i}\)

发现\(ans=\sum_{n=1}^m\sum_{i=0}^m(-1)^if[n][i]\times{3n-x_n-y_n-z_n\choose n-x_n}{2n-y_n-z_n\choose n-y_n}\)

那么设\(g_n=\sum_{i=0}^m(-1)^if[n][i]\),用之前那个递推式可以求出:

\[g_n=\sum_{i能到n}-g_i\times {x_n+y_n+z_n-x_i-y_i-z_i\choose x_n-x_i}{y_n+z_n-y_i-z_i\choose y_n-y_i} \]

就可以做到\(O(m^2)\)了。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define cn const
#define gc getchar()
#define fp(i,a,b) for(rg int i=(a),ed=(b);i<=ed;++i)
#define fb(i,a,b) for(rg int i=(a),ed=(b);i>=ed;--i)
#define go(u) for(rg int i=head[u];~i;i=e[i].nxt)
#define mp make_pair
using namespace std;
typedef cn int cint;
typedef long long LL;
il int rd(){
	rg int x(0),f(1); rg char c(gc);
	while(c<'0'||'9'<c){if(c=='-')f=-1;c=gc;}
	while('0'<=c&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;
	return x*f;
}
cint maxn=100010,maxm=5010,mod=1e9+7;
int n,m,x[maxm],y[maxm],z[maxm];
int f[maxm],fac[maxn*3],ifac[maxn*3],ans;
il int fpow(int a,int b,int ans=1){
	for(;b;b>>=1,a=1ll*a*a%mod)if(b&1)ans=1ll*ans*a%mod;
	return ans;
}
il int C(cint &n,cint &m){return 1ll*fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
int dfs(int u){
	if(f[u])return f[u];
	fp(i,0,m)if(i!=u&&x[i]<=x[u]&&y[i]<=y[u]&&z[i]<=z[u]){
		f[u]=(f[u]-1ll*C(x[u]-x[i]+y[u]-y[i]+z[u]-z[i],x[u]-x[i])*C(y[u]-y[i]+z[u]-z[i],y[u]-y[i])%mod*dfs(i)%mod+mod)%mod;
	}
	return f[u];
}
int main(){
	freopen("a.in","r",stdin);
	freopen("a.out","w",stdout);
	n=rd(),m=rd();
	fp(i,1,m)x[i]=rd(),y[i]=rd(),z[i]=rd();
	fac[0]=1; fp(i,1,n*3)fac[i]=1ll*fac[i-1]*i%mod;
	ifac[n*3]=fpow(fac[n*3],mod-2);
	fb(i,n*3,1)ifac[i-1]=1ll*ifac[i]*i%mod;
	f[0]=1;
	fp(i,1,m)if(!f[i])f[i]=dfs(i);
	fp(i,0,m)ans=(ans+1ll*f[i]*C(n*3-x[i]-y[i]-z[i],n-x[i])%mod*C(n*2-y[i]-z[i],n-y[i]))%mod;
	printf("%d\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值