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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/nobleman__/article/details/79974845

A chess Problem

描述

In chinese chess, “马” is an interesting piece, when it is at position(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),

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

To simplify this problem, when our “马” is at (x,y), it can only move to(x+1,y+2)or(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)
分析:首先是easy,直接递归即可,范围很小, 主要说下medium和hard,我们可以通过平移使得起点始终为(0,0),所以我们只需考虑起点在(0,0) 即可,详见下图
这里写图片描述
根据上图,绿色区域为“马”能走到的坐标,首先可以确定的是,2,3,4,6,7,10,11,15,16,21只能够到达一次,比如5,可以从23坐标到达,而8,可以从45到达,12可以从78到达,现在应该可以找到规律了,如果把整体右旋135o,就变成熟悉的杨辉三角,比如8坐标能到达的方案即为“:C43,到这点了还不够,比如Cnk,我们怎么确定n和k呢,见下图

这里写图片描述

我们先将一点平移至(0,0),(x+y),然后将能到达的坐标延长后,发现(x+y) %3==0,先通过这一条件把一些点特判掉,然后还有延长线中到达不了的,特判掉即可
,我们找到此规律后就好办了,首先是medium,直接预处理出1e5的阶乘(取模后),然后有图找到相应的Cnk即可,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;
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页