您的位置:首页 > 其它

Codeforces Gym 100379J Move the (p, q)-knight to the corner!(DP+lucas定理)

2015-10-28 11:39 417 查看
题意:现在有一个棋盘,要从(1,1)处走到(n,m)处,中间有k个坏点不能走,每次只能走(x+p y+q)或者(x+q, y+p)的位置,问有多少种走法。

思路:这道题是
Codeforces Gym 100589F Count Ways(DP+组合数学) 的强化版。

我们要想办法将这道题转化为这个简化版,考虑这样一个问题,如果从(1,1)走到某一个位置(x,y)那么一定没有或有且仅有一种走法,因为这相当于求一个二元一次方程,也就是说我们把现在点的坐标(x,y)转化为从(1,1)走到位置(x,y)需要竖走几步u和横走几步v,也就是说新的坐标是(u,v)。

因为我们只用到了坏点的坐标和终点的坐标所以我们只需要转换这些点的坐标即可。

注意这道题有两个细节,

一是求解二元一次方程时注意求出来的u,v可能是负的这种情况也是不合题意的(之前一直wa在这里),

二是转换后的坐标不遵从原来的坐标排序关系,因为转换坐标后之前x小的转换后可能u反而大了,所以dp的顺序可能会乱,所以要记录每个坏点之前的序号。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

//const int MAXN = 5000000 + 5;
//const int INF = 0x3f3f3f3f;
LL n, m, p, q, k, cnt;
LL MOD;
LL jc[1001000], inv[1001000];
struct Node {
LL x, y, id;
bool operator < (const Node& A) const {
if(x == A.x) return y < A.y;
return x < A.x;
}
} node[20];
LL dp[20];
LL pow_mod(LL a, LL p, LL n) {
if(p == 0) return 1;
LL ans = pow_mod(a, p/2, n);
ans = ans * ans % n;
if(p%2 == 1) ans = ans * a % n;
return ans;
}
void init() {
inv[0] = jc[0] = 1;
for(int i = 1; i <= 1000010; i++) jc[i] = jc[i-1]*i % MOD;
for(int i = 1; i <= 1000010; i++) inv[i] = inv[i-1]*pow_mod(i, MOD-2, MOD) % MOD;
}
LL c(LL n, LL m) {
return jc
* inv[m] % MOD * inv[n-m] % MOD;
}
LL C(int n, int m) {
LL ret = 1;
while(n>0 && m>0) {
if(n%MOD < m%MOD) return 0;
ret = ret * c(n%MOD, m%MOD) % MOD;
n /= MOD, m /= MOD;
}
return ret;
}
int main() {
//freopen("input.txt", "r", stdin);
scanf("%I64d%I64d%I64d%I64d%I64d%I64d", &p, &q, &MOD, &n, &m, &k);
init();
for(int i = 1; i <= k; i++) scanf("%d%d", &node[i].x, &node[i].y);
node[k+1].x = n, node[k+1].y = m;
cnt = 0;
for(int i = 1; i <= k+1; i++) {
bool tag = 0;
LL ty = ((LL)(node[i].x-1)*p-(LL)(node[i].y-1)*q)/((LL)p*p-(LL)q*q);
LL tx = ((LL)(node[i].x-1)*q-(LL)(node[i].y-1)*p)/((LL)q*q-(LL)p*p);
if(tx>=0 && ty>=0 && tx*p+ty*q==node[i].y-1 && ty*p+tx*q==node[i].x-1) {
node[i].x = tx;
node[i].y = ty;
node[i].id = ++cnt;
node[cnt] = node[i];
tag = 1;
}
if(i==k+1 && !tag) {
puts("0");
return 0;
}
}
sort(node+1, node+cnt+1);
for(int i = 1; i <= cnt; i++) {
for(int j = 1; j < i; j++) {
if(node[j].y <= node[i].y)
dp[i] = (dp[i]-dp[j]*C(node[i].y-node[j].y+node[i].x-node[j].x, node[i].x-node[j].x)) % MOD;
}
dp[i] = (dp[i]+C(node[i].y+node[i].x, node[i].x)+MOD) % MOD;
if(node[i].id == cnt) cout << dp[i] << endl;
}
return 0;
}



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息