UPC-Knight(组合数学基础,逆元)

学习犹如逆水行舟,不进则退

Knight

题目描述

There is a knight - the chess piece - at the origin (0,0) of a two-dimensional grid.
When the knight is at the square (i,j), it can be moved to either (i+1,j+2) or (i+2,j+1).
In how many ways can the knight reach the square (X,Y)?
Find the number of ways modulo 109+7.
Constraints
·1≤X≤106
·1≤Y≤106
·All values in input are integers.

输入

Input is given from Standard Input in the following format:
X Y

输出

Print the number of ways for the knight to reach (X,Y) from (0,0), modulo 109+7.

Sample Input 1

3 3

Sample Output 1

2

Sample Input 2

999999 999999

Sample Output 2

151840682

Sample Input 3

2 2

Sample Output 3

0

题目大意
在国际象棋中,骑士的走法类似中国象棋,不过,它的走法是2+1,
意思是
向前走两格向右走一格
向前走两格向左走一格
向后走两格向右走一格
向后走两格向左走一格
向左走两格向前走一格
向左走两格向后走一格
向右走两格向前走一格
向右走两格向前后一格
共八种走法
如图
在这里插入图片描述
题目想让你算出从(0,0)到(x,y)这个骑士可以走到那一点吗,可悲的是这个骑只能向右或者向上走
也就是如图在这里插入图片描述
算出所有的方案数对109+7取余

思路分析
在这里插入图片描述
和这题方法类似,这个人从A走到B的话有多少种方法呢
也就是他一定要向右走5步,向上走3步。但是在啥时候走右走上这个不确定
那么就可以知道有

C 5 8 C 3 8 56 C_{5}^{8}或C_{3}^{8}种可能,即56种方案
那么这题也类似,这个骑士只能采取向右走二向上走一或者向上走二向右走一的策略,所有说这就好整了,这题就变成了选择多少个方案1和方案2

那么我们就可以解方程
2m+n=X ①
m+2n=Y ②
这样我们就可以求出X和Y的值
可求得
m=(2X-Y)/3
n=(2Y-X)/3
所以说如果m和n不能被3整除那么一定无解
其次就是,在这里插入图片描述
这种走法一定是不可能的,即不能直达使m和n的某个值为负值

之后根据
C m n = n ! ( m ! ) 1 ( ( n m ) ! ) 1 C_{m}^{n}=n!*(m!)^{-1}*((n-m)!)^{-1}
再根据逆元可
逆元对109+7取余
那么就可以使x-1等同于x1e9+5
根据同余模定理,(a*b)%c=a%c×b%c
逆元之后,除变为乘。由此可解

AC时间到

#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
#include<queue>
#include <stack>
#include<string>
#include<utility>
#include<math.h>
#include<stdio.h>
#define PI 3.1415926536
#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
const ll ll_inf = 9223372036854775807;
const int int_inf = 2147483647;
const short short_inf = 32767;
const char char_inf = 127;
inline ll read() {
	ll c = getchar(), Nig = 1, x = 0;
	while (!isdigit(c) && c != '-')c = getchar();
	if (c == '-')Nig = -1, c = getchar();
	while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
	return Nig * x;
}
#define read read()
ll A = 1e9 + 7;
ll B = A - 2;
ll qpow(ll x, ll n, ll mod)
{
	ll res = 1;
	while (n > 0)
	{
		if (n & 1)res = (res * x) % mod;
		x = (x * x) % mod;
		n >>= 1;
	}
	return res;
}
ll fac(ll n)
{
	ll res = 1;
	for (int i = 1; i <= n; i++)
	{
		res *= i;
		res %= A;
	}
	return res;
}
int main()
{
	ll X, Y;
	X = read, Y = read;
	ll m, n;
	m = X + X - Y;
	n = Y + Y - X;
	if (m % 3 || n % 3 || m < 0 || n < 0)
	{
		cout << 0 << endl;
		return 0;
	}
	else
	{
		m /= 3;
		n /= 3;
		ll temp_a = fac(m + n) % A;
		ll temp_b = fac(n) % A;
		ll temp_c = fac(m) % A;
		ll ans = temp_a;
		temp_b = qpow(temp_b, B, A);
		ans = (ans * temp_b) % A;
		temp_c = qpow(temp_c, B, A);
		ans = (ans * temp_c) % A;
		cout << ans % A << endl;
	}
}

当时因为阶乘逆元爆数据不知道怎么处理才无从下手,忘记了逆元之后除变乘。根据逆元,组合数学,同余模定理,快速幂。可求解该题。

书山有路勤为径,学海无涯苦作舟。
发布了32 篇原创文章 · 获赞 12 · 访问量 1188

猜你喜欢

转载自blog.csdn.net/qq_35339563/article/details/104524878
今日推荐