题目链接 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;
}

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

  1. HDU 5794 A Simple Chess (容斥+DP+Lucas)

    A Simple Chess 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5794 Description There is a n×m board ...

  2. HDU 5794 - A Simple Chess

    HDU 5794 - A Simple Chess题意: 马(象棋)初始位置在(1,1), 现在要走到(n,m), 问有几种走法 棋盘上有r个障碍物, 该位置不能走, 并规定只能走右下方 数据范围: ...

  3. HDU 5794 A Simple Chess dp+Lucas

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5794 A Simple Chess Time Limit: 2000/1000 MS (Java/O ...

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

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

  5. hdu 2032 一维数组实现杨辉三角

    杨辉三角 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  6. HDU 5794 A Simple Chess (Lucas + dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794 多校这题转化一下模型跟cf560E基本一样,可以先做cf上的这个题. 题目让你求一个棋子开始在( ...

  7. HDU 5794 A Simple Chess Lucas定理+dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5794 题意概述: 给出一个N*M的网格.网格上有一些点是障碍,不能经过.行走的方式是向右下角跳马步.求 ...

  8. HDU - 5015 233 Matrix(杨辉三角/前缀+矩阵快速幂)

    233 Matrix In our daily life we often use 233 to express our feelings. Actually, we may say 2333, 23 ...

  9. HDU 5794 A Simple Chess ——(Lucas + 容斥)

    网上找了很多人的博客,都看不太懂,还是大力学长的方法好. 要说明的一点是,因为是比较大的数字的组合数再加上mod比较小,因此用Lucas定理求组合数. 代码如下(有注释): #include < ...

随机推荐

  1. 序列内置方法详解(string/list/tuple)

    一.常用方法集合 1.1.string,字符串常用方法 以下举例是python2.7测试: 函数名称 作用 举例 str.capitalize() 字符串第一个字符如果是字母,则把字母替换为大写字母. ...

  2. 在WIN2008R2的IIS7环境下安装PHP5.6.15

    1.下载PHP5.6.15 在http://windows.php.net/download页面中找到VC11 x64 Non Thread Safe下载ZIP版. 2.将下载的压缩包解压到D盘PHP ...

  3. 第一课 项目的介绍 Thinkphp5第四季

    学习地址: https://study.163.com/course/courseLearn.htm?courseId=1004887012#/learn/video?lessonId=1050543 ...

  4. Golang map并发 读写锁

    golang并发 一:只有写操作 var ( count int l = sync.Mutex{} m = make(map[int]int) ) //全局变量并发写 导致计数错误 func vari ...

  5. 下载旧版本的JDK

    下载旧版本的JDK 有的时候我们需要去下载旧版本的JDK,但是进入Oracle官网,显示的总是新版的JDK,这里告诉大家怎么样去下载旧版本的JDK. 首先去JavaSE的 下载界面 拉到最下面,找到这 ...

  6. Linux学习-CentOS 7.x 预设启动的服务简易说明

    这里 仅介绍几个很常见的 daemons 而已,更多的信息呢,就得要麻烦你自己使用 systemctl list-unit-files --type=service 去查询.底下的建议主要是针对 Li ...

  7. 26、android上跑apache的ftp服务

    一.为啥 在android设备跑ftp服务,在现场方便查看日志,目前就是这么用的. 二.前提: 从apache的官网下载依赖包:http://mina.apache.org/ftpserver-pro ...

  8. 一步一步解剖Libevent源代码 - 0

    本系列文章将在<Libevent源码深度解剖>的基础上,结合Libevent-2.0.22代码,更新了其中的一些定义和说明,以及加上了bufferevent部分.   一.Libevent ...

  9. 一张图展示:用两个栈来实现一个队列,完成队列的Push和Pop操作

    一  基本思路 将s1作为存储空间,以s2作为临时缓冲区. 入队时,将元素压入s1. 出队时,将s1的元素逐个“倒入”(弹出并压入)s2,将s2的顶元素弹出作为出队元素,之后再将s2剩下的元素逐个“倒 ...

  10. API生命周期第二阶段——设计:采用swagger进行API描述、设计

    本篇博客主要是以swagger为依托,介绍API生命周期的第二个阶段--设计!在详细介绍之前,我必须声明一点:如果是想了解swagger和项目框架的集成的,这里没有.我要介绍的swagger进行的AP ...