2016多校训练Contest6: 1002 A Simple Chess hdu5794

本文介绍了一个棋盘路径问题,即一枚棋子从棋盘左上角出发,遵循特定的移动规则,避开障碍物,到达右下角的所有可能路径数量。文章提供了一种通过排除障碍物并利用容斥原理解决问题的方法,并给出了具体的实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Problem Description
There is a n×m board, a chess want to go to the position 
(n,m) from the position (1,1).
The chess is able to go to position (x2,y2) from the position (x1,y1), only and if only x1,y1,x2,y2 is satisfied that (x2x1)2+(y2y1)2=5, x2>x1, y2>y1.
Unfortunately, there are some obstacles on the board. And the chess never can stay on the grid where has a obstacle.
I want you to tell me, There are how may ways the chess can achieve its goal.
 

Input
The input consists of multiple test cases.
For each test case:
The first line is three integers, n,m,r,(1n,m1018,0r100), denoting the height of the board, the weight of the board, and the number of the obstacles on the board.
Then follow r lines, each lines have two integers, x,y(1xn,1ym), denoting the position of the obstacles. please note there aren't never a obstacles at position (1,1).
 

Output
For each test case,output a single line "Case #x: y", where x is the case number, starting from 1. And y is the answer after module 110119.
 

Sample Input
1 1 0 3 3 0 4 4 1 2 1 4 4 1 3 2 7 10 2 1 2 7 1
 

Sample Output
Case #1: 1 Case #2: 0 Case #3: 2 Case #4: 1 Case #5: 5


似乎数据特别水。。只要把不可到达的点删掉然后2^k容斥就可以直接过了。。并不明白怎么造的数据

正常的做法的话。。

我们用f[i]维护到某个障碍前面不经过任何障碍的方案数

然后转移的时候算出1,1到i的次数,

枚举1到i-1所有的障碍,乘走过中间部分的方案数,把这些减去

最后r+1加入终点

ans就是f[r+1]

这样复杂度是r^2的。

1,1到x,y的方案数,我们考虑马的走法,可以换成先往右下走一格,然后往右或者往下走。

因为总步数一定,所以可以组合数求解

拖了个lucas模版

#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct obstacles
{
	long long x,y;
	bool operator <(obstacles z) const
	{
		return x<z.x||x==z.x&&y<z.y;
	}
}a[1001];
long long f[1001];
long long mod=110119;
long long p1[1000001],p2[1000001];
inline long long PowMod(long long a,long long b)
{  
    long long ret=1;  
    while(b)
	{  
        if(b&1)
			ret=(ret*a)%mod;  
        a=(a*a)%mod;  
        b>>=1;  
    }  
    return ret;  
}  
long long fac[1000005];  
inline long long Get_Fact(long long p)
{  
    fac[0]=1;  
    for(int i=1;i<=p;i++)  
        fac[i]=(fac[i-1]*i)%p;  
}  
inline long long Lucas(long long n,long long m,long long p)
{  
    long long ret=1;  
    while(n&&m)
	{  
        long long a=n%mod,b=m%mod;  
        if(a<b) return 0;  
        ret=(ret*fac[a]*PowMod(fac[b]*fac[a-b]%p,p-2))%p;  
        n/=p;  
        m/=p;  
    }  
    return ret;  
} 
inline long long cale(int i,int j)
{
	long long n=a[j].x-a[i].x,m=a[j].y-a[i].y;
	if((m+n)%(long long)3!=0)
		return 0;
	long long step=(m+n)/(long long)3;
	n-=step;
	m-=step;
	if(n<0||m<0)
		return 0;
	return Lucas(n+m,m,mod);
}
inline bool check(int i,int j)
{
	if(a[i].x>a[j].x||a[i].y>a[j].y)
		return false;
	return true;
}
int main()
{
	Get_Fact(mod);
	int k=0;
	long long n,m;
	int r;
	while(scanf("%I64d%I64d%d",&n,&m,&r)!=EOF)
	{
		k++;		
		int i,j;
		for(i=1;i<=r;i++)
			scanf("%I64d%I64d",&a[i].x,&a[i].y);
		r++;
		a[i].x=n;
		a[i].y=m;
		sort(a+1,a+1+r);
		a[0].x=1;
		a[0].y=1;
		f[0]=1;
		for(i=1;i<=r;i++)
		{
			f[i]=cale(0,i);
			for(j=1;j<=i-1;j++)
			{
				if(check(j,i))
					f[i]-=f[j]*cale(j,i)%mod;
				while(f[i]<0)
					f[i]+=mod;
			}
		}
		printf("Case #%d: %I64d\n",k,f[r]);
	}
	return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值