A Simple Chess

一、题目

点此看题

马走日,问禁止一些点的情况下起点到终点的方案数,模 110119 110119

二、解法

先考虑没有限制两个点的情况,设 x x 方向需要移动 a a y y 方向需要移动 b b ,设 p = ( a + b ) / 3 p=(a+b)/3 ,所以方案数是 C ( p , a p ) C(p,a-p) ,就是说每一步 x , y x,y 都会至少靠近 1 1 ,而 x x 还需要走额外 a p a-p 步,就从 p p 步中选。

然后我们先把给出的禁止点排序,按照 x + y x+y 的和从大到小,因为它们一定满足一个拓扑序,然后还要考虑去重,设 d p [ i ] dp[i] 为到第 i i 个禁止点未经过任何前面的禁止点的方案数(所以我们需要把 ( n , m ) (n,m) 插入进去,方便统计答案),转移如下:
d p [ i ] = w a y ( ( 1 , 1 ) , i ) j = 1 i 1 d p [ j ] × w a y ( j , i ) dp[i]=way((1,1),i)-\sum_{j=1}^{i-1} dp[j]\times way(j,i) 其中 w a y way 的方法上面已经讲过了,用 l u c a s lucas 算一算就行。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define int long long
const int M = 105;
const int MOD = 110119;
int read()
{
    int x=0,flag=1;char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,k,dp[M],fac[MOD+5],inv[MOD+5];
void init(int n)
{
	fac[0]=inv[0]=inv[1]=1;
	for(int i=2;i<n;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
	for(int i=2;i<n;i++) inv[i]=inv[i]*inv[i-1]%MOD;
	for(int i=1;i<n;i++) fac[i]=fac[i-1]*i%MOD;
}
int C(int n,int m)
{
	if(m>n) return 0;
	return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int lucas(int n,int m)
{
	if(m==0) return 1;
	return lucas(n/MOD,m/MOD)*C(n%MOD,m%MOD)%MOD;
}
struct node
{
	int x,y;
	node(int X=0,int Y=0) : x(X) , y(Y) {}
	bool operator < (const node &b) const
	{
		return x+y<b.x+b.y;
	}
	int check(const node &t) const
	{
		if(x<=t.x || y<=t.y) return 0;
		int a=x-t.x,b=y-t.y;
		if((a+b)%3!=0 || a>2*b || b>2*a) return 0;
		return 1;
	}
	int cnt(const node &t) const
	{
		int a=x-t.x,b=y-t.y;
		int p=(a+b)/3;
		return lucas(p,a-p);
	}
}a[M];
signed main()
{
	init(MOD);
	int Case=0;
	while(~scanf("%lld %lld %lld",&n,&m,&k))
	{
		memset(dp,0,sizeof dp);
		int f=0;
		for(int i=1;i<=k;i++)
		{
			a[i].x=read();
			a[i].y=read();
			if(a[i].x==n && a[i].y==m) f=1;
		}
		printf("Case #%d: ",++Case);
		if(n==1 && m==1)
		{
			puts("1");
			continue; 
		}
		if(f==1)
		{
			puts("0");
			continue;
		}
		sort(a+1,a+1+k);
		a[++k].x=n;a[k].y=m;
		for(int i=1;i<=k;i++)
		{
			if(!a[i].check(node(1,1))) continue;
			dp[i]=a[i].cnt(node(1,1));
			for(int j=1;j<k;j++)
			{
				if(!a[i].check(a[j])) continue;
				dp[i]=(dp[i]-dp[j]*a[i].cnt(a[j]))%MOD;
			}
		}
		printf("%d\n",(dp[k]+MOD)%MOD);
	}
}
原创文章 430 获赞 14 访问量 1万+

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/105799805