14th SWJTUCPC Warming Up A chess Problem 【easy】【medium】【hard】【组合数 + lucas】

A chess Problem

描述

In chinese chess, “马” is an interesting piece, when it is at position (x,y) ( x , y ) , it can move to (x2,y1),(x2,y+1),(x1,y2),(x1,y+2),(x+1,y2),(x+1,y+2),(x+2,y1),(x+2,y+1) ( x − 2 , y − 1 ) , ( x − 2 , y + 1 ) , ( x − 1 , y − 2 ) , ( x − 1 , y + 2 ) , ( x + 1 , y − 2 ) , ( x + 1 , y + 2 ) , ( x + 2 , y − 1 ) , ( x + 2 , y + 1 ) ,

Now the problem is, when a “马” is at position (x,y), how many ways does it have for he to move to (x0,y0). ( x 0 , y 0 ) .

To simplify this problem, when our “马” is at (x,y), it can only move to (x+1,y+2)or(x+2,y+1) ( x + 1 , y + 2 ) o r ( x + 2 , y + 1 )

easy输入

The first line: the number of case T(≤T≤100)
Then T lines follow, each line contains four integers: x,y,x0,y0(0≤x,y,x0,y0≤8) - the position the “马” at and the position it want’s to go.

easy输出

For each case, out put an integer ans one line – the number of the ways to go from (x,y) to (x0,y0)

medium输入

The first line: the number of case T(≤T≤1000)
Then T lines follow, each line contains four integers: x,y,x0,y0(0≤x,y,x0,y0≤100000) - the position the “马” at and the position it want’s to go.

medium输出

For each case, out put an integer ans one line – the number of the ways to go from (x,y) to (x0,y0) mod 109+7

hard输入

The first line: the number of case T(≤T≤1000)
Then T lines follow, each line contains four integers: x,y,x0,y0(0≤x,y,x0,y0≤10000000) - the position the “马” at and the position it want’s to go.

hard输出

For each case, out put an integer ans one line – the number of the ways to go from (x,y) to (x0,y0) mod 104+7

样例输入1

3
0 0 3 3
0 0 6 6
3 3 6 6

样例输出1

2
6
2

提示

In the first example:

(0,0)−>(2,1)−>(3,3),(0,0)−>(1,2)−>(3,3)
In the second example:

(0,0)−>(2,1)−>(4,2)−>(5,4)−>(6,6),(0,0)−>(2,1)−>(3,3)−>(5,4)−>(6,6)
(0,0)−>(2,1)−>(3,3)−>(4,5)−>(6,6),(0,0)−>(1,2)−>(3,3)−>(5,4)−>(6,6)
(0,0)−>(1,2)−>(3,3)−>(4,5)−>(6,6),(0,0)−>(1,2)−>(2,4)−>(4,5)−>(6,6)
In the third example:

(3,3)−>(5,4)−>(6,6),(3,3)−>(4,5)−>(6,6)

题意:给你一个棋盘,难度不同,大小不同,给你起点和终点,问你有多少种方式可以从起点到达终点,你当前只能有两个位置可以走,假设你在 (x,y),(x+2,y+1)(x+1,y+2) ( x , y ) , 你 只 能 走 到 ( x + 2 , y + 1 ) 或 ( x + 1 , y + 2 )
分析:首先是easy,直接递归即可,范围很小, 主要说下medium和hard,我们可以通过平移使得起点始终为 (0,0) ( 0 , 0 ) 点 ,所以我们只需考虑起点在 (0,0) ( 0 , 0 ) 即可,详见下图
这里写图片描述
根据上图,绿色区域为“马”能走到的坐标,首先可以确定的是,2,3,4,6,7,10,11,15,16,21只能够到达一次,比如5,可以从23坐标到达,而8,可以从45到达,12可以从78到达,现在应该可以找到规律了,如果把整体右旋 135o 135 o ,就变成熟悉的杨辉三角,比如8坐标能到达的方案即为“: C34 C 4 3 ,到这点了还不够,比如 Ckn C n k ,我们怎么确定n和k呢,见下图

这里写图片描述

我们先将一点平移至 (0,0),(x+y) ( 0 , 0 ) 点 , 另 一 点 记 为 : ( x ′ + y ′ ) ,然后将能到达的坐标延长后,发现 (x+y) ( x ′ + y ′ ) %3==0 % 3 == 0 ) ,先通过这一条件把一些点特判掉,然后还有延长线中到达不了的,特判掉即可
,我们找到此规律后就好办了,首先是medium,直接预处理出1e5的阶乘(取模后),然后有图找到相应的 Ckn C n k 即可,hard里我们利用Lucas可以快速求大整数取模,详见代码

参考代码

// medium

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
using namespace std;
const int maxn = 1e5 + 10;

const int MOD = 1e9 + 7;
typedef long long ll;

#define mod(x) ((x) % MOD)

ll qpow(ll a,ll b) {
    ll res = 1;
    while (b) {
        if(b & 1) {
            res = mod(res * a);
        }
        a = mod(a * a);
        b >>= 1;
    }
    return res;
}
ll x,y,xx,yy;
ll fac[maxn], rfac[maxn];


void init() {
    fac[0] = 1;
    for (int i = 1; i <= maxn; i++)
        fac[i] = mod(fac[i - 1] * i);
    rfac[maxn] = qpow(fac[maxn],MOD - 2);
    for (int i = maxn;i > 0; i--)
        rfac[i - 1] = mod(rfac[i] * i);
}
int main(){
    int T; cin>>T;
    init();
    while (T--) {
        cin>>x>>y>>xx>>yy;
        ll ex = xx - x;
        ll ey = yy - y;
        if(ex <= 0 || ey <= 0 || (ex + ey) % 3 != 0) {
            puts("0");
        } else {
            ll t = (ex + ey) / 3;
            ll bo = t;
            ll up = t + t;
            if(ey < bo || ey > up) {
                puts("0");
            } else {
                ll k = ey - t;
                ll n = t;
                cout<<mod(fac[n] * 1ll*mod(rfac[k]*1ll*rfac[n - k]))<<endl;
            }
        }
    }
    return 0;
}

参考代码

// hard
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <map>
using namespace std;
const int maxn = 1e5 + 7;

const int MOD = 1e4 + 7;
typedef long long ll;

#define mod(x) ((x) % MOD)

ll qpow(ll a,ll b) {
    ll res = 1;
    while (b) {
        if(b & 1) {
            res = mod(res * a);
        }
        a = mod(a * a);
        b >>= 1;
    }
    return res;
}

ll x,y,xx,yy;

ll C(ll nn, ll mm) {
    ll up = 1, down = 1;
    for (int i = nn - mm + 1; i <= nn; i++) up = mod(up * 1ll *i);
    for (int i = 1; i <= mm; i++) down = mod(down * 1ll *i);
    return mod(up * qpow(down, MOD - 2));
}

ll lucas(ll n, ll m) {
    if(m == 0) return 1;
    return mod(lucas(n / MOD, m / MOD) * 1ll * C(n % MOD,m % MOD));
}

int main(){
    int T; cin>>T;
    while (T--) {
        cin>>x>>y>>xx>>yy;
        ll ex = xx - x;
        ll ey = yy - y;
        if(ex <= 0 || ey <= 0 || (ex + ey) % 3 != 0) {
            puts("0");
        } else {
            ll t = (ex + ey) / 3;
            ll bo = t;
            ll up = t + t;
            if(ey < bo || ey > up) {
                puts("0");
            } else {

                ll k = ey - t;
                ll n = t;
                cout<<lucas(n,k)<<endl;
            }
        }
    }
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值