SRM 498 FoxJumping(dp+容斥)

32 篇文章 0 订阅
4 篇文章 0 订阅

传送门
神题 O r z Orz Orz

先预处理出三个 d p dp dp数组:

f x i , j fx_{i,j} fxi,j表示横向不加限制走 i i i步走到 j j j的方案数。

f y i , j fy_{i,j} fyi,j表示纵向不加限制走 i i i步走到 j j j的方案数。

f i , j f_{i,j} fi,j表示走 i i i步每次只能走被限制的步数最终走 j j j格方案数。

然后就可以xjb容斥就能算出答案。
显然可以枚举走几步非法的得出答案。
代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
const int rlen=1<<18|1;
inline char gc(){
	static char buf[rlen],*ib,*ob;
	(ib==ob)&&(ob=(ib=buf)+fread(buf,1,rlen,stdin));
	return ib==ob?-1:*ib++;
}
inline int read(){
	int ans=0;
	char ch=gc();
	while(!isdigit(ch))ch=gc();
	while(isdigit(ch))ans=((ans<<2)+ans<<1)+(ch^48),ch=gc();
	return ans;
}
const int mod=1e4+7;
inline int add(const int&a,const int&b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(const int&a,const int&b){return a>=b?a-b:a-b+mod;}
inline int mul(const int&a,const int&b){return a*b>=mod?a*b-a*b/mod*mod:a*b;;}
inline void Add(int&a,const int&b){a=a+b>=mod?a+b-mod:a+b;}
inline void Dec(int&a,const int&b){a=a>=b?a-b:a-b+mod;}
inline void Mul(int&a,const int&b){a=a*b>=mod?a*b-a*b/mod*mod:a*b;}
const int N=1605,M=805;
class FoxJumping{
	public:
	int R,K,n,m,a,b,fx[N][M],fy[N][M],f[N][M],C[N][N],ss[M],ban[55],mx=0;
	inline int getsum(int l,int r){return dec(ss[r],l?ss[l-1]:0);}
	int Main(){
		for(ri i=0;i<=R;++i){
			C[i][0]=C[i][i]=1;
			for(ri j=1;j<i;++j)C[i][j]=add(C[i-1][j-1],C[i-1][j]);
		}
		fx[0][0]=1;
		for(ri i=0;i<=n;++i)ss[i]=1;
		for(ri i=1;i<=R;++i){
			for(ri j=0;j<=n;++j)fx[i][j]=getsum(max(j-a,0),j);
			for(ri j=0;j<=n;++j)ss[j]=add(j?ss[j-1]:0,fx[i][j]);
		}
		fy[0][0]=1;
		for(ri i=0;i<=m;++i)ss[i]=1;
		for(ri i=1;i<=R;++i){
			for(ri j=0;j<=m;++j)fy[i][j]=getsum(max(j-b,0),j);
			for(ri j=0;j<=m;++j)ss[j]=add(j?ss[j-1]:0,fy[i][j]);
		}
		f[0][0]=1;
		for(ri i=1;i<=R;++i){
			for(ri j=0,up=min(mx*i,min(n,m));j<=up;j+=10){
				for(ri k=1;k<=K;++k){
					if(ban[k]>j)continue;
					Add(f[i][j],f[i-1][j-ban[k]]);
				}
			}
		}
		int ans=0;
		for(ri i=0,t=0;i<=R;++i,t=0){
			for(ri up=min(i*mx,min(n,m)),j=0;j<=up;j+=10)Add(t,mul(f[i][j],mul(fx[R-i][n-j],fy[R-i][m-j])));
			Mul(t,C[R][i]);
			i&1?Dec(ans,t):Add(ans,t);
		}
		return ans;
	}
	inline int getCount(int n_, int m_, int a_, int b_, int R_,vector<int>t){
		n=n_,m=m_,a=a_,b=b_,R=R_,K=t.size();
		bool ff=0;
		for(ri i=1;i<=K;++i)ff|=(ban[i]=t[i-1])==0,mx=max(mx,ban[i]);
		if(!ff)ban[++K]=0;
		return Main();
	}
};
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值