题目大意:
就是现在一个n*m的棋盘上有一个位于顶点的马(1, 1), 现在要从(1, 1)移动到(n, m), 中间有k个位置是不能走的 k <= 10
并且每次走的时候必须遵循马走的规则: 从(x , y)走到(x + p, y + q)或者 (x + q, y + p)
n, m <= 1e9, k <= 10, p, q <= 20问从起点走到终点必经过坏点的路线有多少种, 结果对d取模 (d <= 1e6)
大致思路:
首先考虑每一个位置(x, y)到达这个位置需要的两种走法的次数分别是t1, t2, 那么 t1*p + t2*q == y, t1*q + t2*p == x
也就是说每一个位置(x, y)都可以转换成坐标(tmpx = 1, tmpy + 1)其中 tmpx = abs(ty*p - tx*q) / abs(p*p - q*q), tmpy = abs(ty*q - p*tx) / abs(q*q - p*p);
也就是将元问题转换成从左上角(1, 1)走到右下角(new_n, new_m)的方案数, 每次向右或者向下走一步(x + 1, y)或(x, y + 1)不经过换点到终点的步数
于是这个DP就和Codeforces 559C一样了, 需要注意的是处理组合数不可能将所有的阶乘以及逆元预处理出来
而组合数C[x][y]中x, y <= 2e9于是需要用到Lucas定理, 因为d <= 1e6于是就处理1e6以内的阶乘就可以了
Lucas定理: Lucas(x, y, mod) = C(x % mod, y % mod)*Lucas(x / mod, y / mod, mod) % mod
代码如下:
Result : Accepted Memory : 7826 ms Time : 62 ms
/* * Author: Gatevin * Created Time: 2015/8/14 13:24:30 * File Name: Sakura_Chiyo.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; struct Point { lint x, y; int id; Point(){} Point(lint _x, lint _y, int _id) { x = _x; y = _y; id = _id; } }; bool cmp(Point p1, Point p2) { return p1.x < p2.x || (p1.x == p2.x && p1.y < p2.y); } Point P[20]; lint p, q, mod; lint n, m; int k; lint dp[100]; lint fac[1000010]; lint quick(lint base, lint pow) { lint ret = 1; while(pow) { if(pow & 1) ret = ret*base % mod; pow >>= 1; base = base*base % mod; } return ret; } lint get(lint x, lint y)//C[x][y], x, y <= 1e6 { return fac[x]*quick(fac[y]*fac[x - y] % mod, mod - 2); } //Lucas(x, y, mod) = C(x % mod, y % mod)*Lucas(x/mod, y/mod, mod) % mod lint C(lint x, lint y)//C[x][y], x, y <= 1e9 { lint ret = 1; while(x > 0 && y > 0) { if(x % mod < y % mod) return 0; ret = ret*get(x % mod, y % mod) % mod; x /= mod, y /= mod; } return ret; } int main() { while(~scanf("%I64d %I64d %I64d", &p, &q, &mod)) { fac[0] = 1; for(int i = 1; i <= mod; i++) fac[i] = fac[i - 1]*i % mod; scanf("%I64d %I64d", &n, &m); P[0].x = P[0].y = 1; P[0].id = 0; int cnt = 0; scanf("%d", &k); for(int i = 1; i <= k; i++) { lint tx, ty; scanf("%I64d %I64d", &tx, &ty); tx--, ty--; lint tmpx = abs(ty*p - tx*q) / abs(p*p - q*q), tmpy = abs(ty*q - p*tx) / abs(q*q - p*p); if(tmpx*p + tmpy*q == ty && tmpx*q + tmpy*p == tx) { ++cnt; P[cnt] = Point(tmpx + 1, tmpy + 1, cnt); } } n--, m--; lint tmpx = abs(m*p - n*q) / abs(p*p - q*q), tmpy = abs(m*q - p*n) / abs(q*q - p*p); if(tmpx*p + tmpy*q != m || tmpx *q + tmpy*p != n) { puts("0"); continue; } ++cnt; P[cnt] = Point(abs(m*p - n*q) / abs(p*p - q*q) + 1, abs(m*q - p*n) / abs(q*q - p*p) + 1, cnt); sort(P, P + cnt + 1, cmp); dp[0] = 1; for(int i = 1; i <= cnt; i++) { dp[i] = C(P[i].x - P[0].x + P[i].y - P[0].y, P[i].x - P[0].x); for(int j = 1; j < i; j++) if(P[j].y <= P[i].y) dp[i] = (dp[i] - dp[j]*C(P[i].x - P[j].x + P[i].y - P[j].y, P[i].x - P[j].x) % mod + mod) % mod; if(P[i].id == cnt) { printf("%I64d\n", dp[i]); break; } } } return 0; } /* 1 2 997 10 10 3 5 9 6 2 3 2 */