HDU 5794 A Simple Chess(杨辉三角+容斥原理+Lucas)

题目链接 A Simple Chess

打表发现这其实是一个杨辉三角……

然后发现很多格子上方案数都是0

对于那写可能可以到达的点(先不考虑障碍点),我们先叫做有效的点

对于那些障碍,如果不在有效点上,则自动忽略

障碍$(A, B)$如果有效,那么就要进行如下操作:

以这个点为一个新的杨辉三角的顶点,算出目标点的坐标$(x, y)$。

目标点的答案减去$C(A, B) * C(x, y)$的值。

但是这样会造成重复计算,原因是障碍之间可能有相互影响的关系。

这个时候就要考虑容斥原理,DFS消除这些重复计算即可。

计算组合数的时候可以用两种方法,

一种是快速幂

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

#define fi		first
#define se		second

typedef long long LL;

const int N  = 120010;
const int A  = 210;
const LL mod = 110119;

struct node{
	LL x, y;
	friend bool operator < (const node &a, const node &b){
		return (a.x + a.y) / 3 < (b.x + b.y) / 3;
	}
} c[A];

int r, cnt;
LL x, y, n, m, nx, ny, ans;
LL fac[N], a[A], b[A], f[A][A];

inline LL Pow(LL a, LL b, LL Mod){ LL ret(1); for (; b; b >>= 1, (a *= a) %= Mod) if (b & 1) (ret *= a) %= Mod; return ret;}
inline LL C(LL n, LL m){ return m > n ? 0 : fac[n] * Pow(fac[m] * fac[n - m] % mod, mod - 2, mod) % mod; }

LL Lucas(LL n, LL m){
	if (m > n / 2) m = n - m;
	return m == 0 ? 1 : C(n % mod, m % mod) % mod * (Lucas(n / mod, m / mod) % mod) % mod;
}

inline LL calc(LL x, LL y){
	LL n = (x + y) / 3;
	LL m = y - n - 1;
	return Lucas(n, m);
}

inline bool check(LL x, LL y){
	if (x < 0 || y < 0 || (x + y) % 3 != 2) return false;
	LL n = (x + y) / 3;
	if (x < n + 1 || y < n + 1) return false;
	return true;  

}

void dfs(int pre, int pos, int d, LL tmp){
	if (tmp == 0LL) return;
	if (d & 1) ans = (ans - tmp * b[pos] % mod) % mod;
	else ans = (ans + tmp * b[pos] % mod) % mod;
	rep(i, pos + 1, cnt) dfs(pos, i, d + 1, tmp * f[pos][i] % mod);
}	

int main(){

	fac[0] = 1; rep(i, 1, N - 10) fac[i] = (fac[i - 1] * i) % mod;

	int ca = 0;
	while (~scanf("%lld%lld%d", &n, &m, &r)){
		memset(a, 0, sizeof a);
		memset(b, 0, sizeof b);
		memset(c, 0, sizeof c);
		memset(f, 0, sizeof f);
		cnt = 0;
		rep(i, 1, r){
			scanf("%lld%lld", &x, &y);
			if (check(x, y)){
				++cnt;
				c[cnt].x = x;
				c[cnt].y = y;

			}
		}

		printf("Case #%d: ", ++ca);
		if (!check(n, m)){
			puts("0");
			continue;
		}

		LL x1 = (n + m) / 3, y1 = n - x1 - 1;
		ans = Lucas(x1, y1);
		sort(c + 1, c + cnt + 1);
		rep(i, 1, cnt){
			a[i] = calc(c[i].x, c[i].y);
			nx = n - c[i].x + 1;
			ny = m - c[i].y + 1;
			if (check(nx, ny)) b[i] = calc(nx, ny);

			rep(j, i + 1, cnt){
				nx = c[j].x - c[i].x + 1;
				ny = c[j].y - c[i].y + 1;
				if (check(nx, ny)) f[i][j] = calc(nx, ny);
			}
		}

		rep(i, 1, cnt) dfs(-1, i, 1, a[i]);
		printf("%lld\n", (ans + mod) % mod);
	}

	return 0;
}

另一种是扩展欧几里得。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b)	for (int i(a); i <= (b); ++i)
#define dec(i, a, b)	for (int i(a); i >= (b); --i)

#define fi		first
#define se		second

typedef long long LL;

const int N  = 120010;
const int A  = 210;
const LL mod = 110119;

struct node{
	LL x, y;
	friend bool operator < (const node &a, const node &b){
		return (a.x + a.y) / 3 < (b.x + b.y) / 3;
	}
} c[A];

int r, cnt;
LL x, y, n, m, nx, ny, ans;
LL fac[N], a[A], b[A], f[A][A];

void exgcd(LL a, LL b, LL &x, LL &y){
	if (b == 0){ x = 1, y = 0; return;}
	exgcd(b, a % b, x, y);
	LL tmp = x; x = y; y = tmp - (a / b) * y;
}

LL C(LL n, LL m){
	if (m > n)  return 0LL;
	if (n == m) return 1LL;
	LL cnt, x, y;
	cnt = m;
	m = fac[n];
	n = fac[cnt] * fac[n - cnt] % mod;
	exgcd(n, mod, x, y);
	x *= m;
	x %= mod;
	if (x < 0) x += mod;
	return x;
}

LL Lucas(LL n, LL m){
	if (m > n / 2) m = n - m;
	if (m == 0) return 1;
	return C(n % mod, m % mod) % mod * (Lucas(n / mod, m / mod) % mod) % mod;
}

inline LL calc(LL x, LL y){
	LL n = (x + y) / 3;
	LL m = y - n - 1;
	return Lucas(n, m);
}

inline bool check(LL x, LL y){
	if (x < 0 || y < 0 || (x + y) % 3 != 2) return false;
	LL n = (x + y) / 3;
	if (x < n + 1 || y < n + 1) return false;
	return true;  

}

void dfs(int pre, int pos, int d, LL tmp){
	if (tmp == 0LL) return;
	if (d & 1) ans = (ans - tmp * b[pos] % mod) % mod;
	else ans = (ans + tmp * b[pos] % mod) % mod;
	rep(i, pos + 1, cnt) dfs(pos, i, d + 1, tmp * f[pos][i] % mod);
}	

int main(){

	fac[0] = 1; rep(i, 1, N - 10) fac[i] = (fac[i - 1] * i) % mod;

	int ca = 0;
	while (~scanf("%lld%lld%d", &n, &m, &r)){
		memset(a, 0, sizeof a);
		memset(b, 0, sizeof b);
		memset(c, 0, sizeof c);
		memset(f, 0, sizeof f);
		cnt = 0;
		rep(i, 1, r){
			scanf("%lld%lld", &x, &y);
			if (check(x, y)){
				++cnt;
				c[cnt].x = x;
				c[cnt].y = y;

			}
		}

		printf("Case #%d: ", ++ca);
		if (!check(n, m)){
			puts("0");
			continue;
		}

		LL x1 = (n + m) / 3, y1 = n - x1 - 1;
		ans = Lucas(x1, y1);
		sort(c + 1, c + cnt + 1);
		rep(i, 1, cnt){
			a[i] = calc(c[i].x, c[i].y);
			nx = n - c[i].x + 1;
			ny = m - c[i].y + 1;
			if (check(nx, ny)) b[i] = calc(nx, ny);

			rep(j, i + 1, cnt){
				nx = c[j].x - c[i].x + 1;
				ny = c[j].y - c[i].y + 1;
				if (check(nx, ny)) f[i][j] = calc(nx, ny);
			}
		}

		rep(i, 1, cnt) dfs(-1, i, 1, a[i]);
		printf("%lld\n", (ans + mod) % mod);
	}

	return 0;
}
时间: 2024-10-24 09:24:06

HDU 5794 A Simple Chess(杨辉三角+容斥原理+Lucas)的相关文章

HDU 5794 A Simple Chess(卢卡斯定理 + 容斥原理)

传送门 A Simple Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 667    Accepted Submission(s): 168 Problem Description There is a n×m board, a chess want to go to the position (n,m) from the

2014多校第六场 || HDU 4927 Series 1(杨辉三角组合数)

题目链接 题意 : n个数,每操作一次就变成n-1个数,最后变成一个数,输出这个数,操作是指后一个数减前一个数得到的数写下来. 思路 : 找出几个数,算得时候先不要算出来,用式子代替,例如: 1 2 3 4 5 6 (2-1) (3-2) (4-3) (5-4)(6-5) (3-2-2+1)(4-3-3+2)(5-4-4+3)(6-5-5+4) (4-3-3+2-3+2+2-1)(5-4-4+3-4+3+3-2)(6-5-5+4-5+4+4-3) (5-4-4+3-4+3+3-2-4+3+3-2

HDU 5794 A Simple Chess (Lucas + dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794 多校这题转化一下模型跟cf560E基本一样,可以先做cf上的这个题. 题目让你求一个棋子开始在(1,1),只能像马一样走且往右下方走,不经过坏点,有多少种走法能到达(n,m)点. 比如n=6, m=5 有两个坏点,模型转换 如下图: 转换成简单模型之后,只要把棋子可能经过的坏点存到结构体中,按照x与y从小到大排序. dp[i]表示从起点到第i个坏点且不经过其他坏点的方案数. dp[i] = L

HDU 5794 A Simple Chess

可以用总方案数减去经过障碍物的方案数. 先写一个判断某点是否可达的函数~ check(a,b) 再写一个某点到某点的方案数的函数~ cal(x1,x2,y1,y2) 设随便走 从(1,1)到(n,m)的方案数为P 设从(1,1)走到第i个障碍物并且不经过其余障碍物的方案数为num[i]. 那么 answer = P - sum{ num[i] * cal(x[i],y[i],n,m) }. 计算num[i] 可以将所有的障碍物按照x从小到大排个序,然后o(r*r)效率得到. #pragma co

HDU 4927 Series 1(高精度+杨辉三角)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4927 解题报告:对于n,结果如下: C(0,n-1) *A[n] - C(1,n-1) * A[n-1] + C(2,n-1) * A[n-2] - C(3,n-1) * A[n-3] ....... C(n-1,n-1) * A[1]; n <= 3000,到了后面二项式会很大,因为要用到高精度的乘法和除法,所以直接用java的大数类写了,简单多了. 1 import java.math.BigI

HDU 6129 Just do it 数学 杨辉三角 递推

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=6129 题目描述: 将a序列转化成b序列, b[i] = a[1]^a[2]^a[3]^a[4]^......^a[i] 重复m次, 求b 解题思路: 我开始找的是系数的规律发现他满足杨辉三角, 也就是说我现在给出n 和 m , 然后求最后一项是奇数还是偶数, 然后自己就死推呀, 推了两个多点儿把所有的表都打遍了也没找到规律.....其实是有公式的......: C(x+y-2, y-2) 表示第i

POJ 3146 &amp; HDU 3304 Interesting Yang Yui Triangle(杨辉三角)

题目链接: HDU 3304 :http://acm.hdu.edu.cn/showproblem.php?pid=3304 POJ 3146  :http://poj.org/problem?id=3146 Problem Description Harry is a Junior middle student. He is very interested in the story told by his mathematics teacher about the Yang Hui trian

HDU 2032 杨辉三角

杨辉三角 Problem Description 还记得中学时候学过的杨辉三角吗?具体的定义这里不再描述,你可以参考以下的图形: 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 Input 输入数据包含多个测试实例,每个测试实例的输入只包含一个正整数n(1<=n<=30),表示将要输出的杨辉三角的层数. Output 对应于每一个输入,请输出相应层数的杨辉三角,每一层的整数之间用一个空格隔开,每一个杨辉三角后面加一个空行. Sample Input 2

hdu 2032 杨辉三角 (java)

问题: 本题要求看出杨辉三角的规律,即:a[i][j]=a[i-1][j-1]+a[i-1][j]; 在输出的时候第一列没有输出,原因是j参数设置的是从1开始的,故将其改为0,用if满足j从一开始的需求就可以了. 杨辉三角 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 43154    Accepted Submission(s):