XJOI模拟训练9 - B.小Z的城市之旅

小Z的城市之旅 :

题目描述 :

小Z目前位于平面直角坐标系上的(0,0)点,想要前往机房所在的(x,y)点。小Z住在一个规划整齐的城市中,每个单位时间能向上下左右四个方向中的一个移动一个单位。小Z希望自己在R时间后恰好位于(x,y)点。小Z想知道有多少合法的移动序列能达到这个目的。

输入格式 :

第一行一个整数T,表示数据组数。
接下来T行,每行三个整数x,y,r。

输出格式 :

输出T行,每行一个整数
表示合法的移动序列数量对998244353取模。

样例 :

输入 :

3
1 1 2
1 1 4
15 15 40

输出 :

2
24
218032581

数据范围 :

对于20%的数据,T<=10,R<=10;
对于40%的数据,T<=10,R<=100;
对于60%的数据,T<=10,R<=200000;
对于100%的数据,T<=100000,R<=200000;

Solution & Code :

设终点为\((R_x,R_y)\)
设小Z向左走了a步,向右走了x步,向下走了b步,向上走了y步
可得 :
\(x-a=R_x\)
\(y-b=R_y\)
\(x+y+a+b=R\)
可化为 :
\(a+b=(R-R_x-R_y)/2\)
\(x+y=(R+R_x+R_y)/2\)
于是题意可以理解为 :
在长度为 R 的序列中选择填入 a和b 共\((R-R_x-R_y)/2\)个,x和y共\((R+R_x+R_y)/2\)个的方案数
设 :
\((R-R_x-R_y)/2 = K1\)
\((R+R_x+R_y)/2 =K2\)

可得 : (i 表示 枚举 a 的放入个数)
\(Ans = C(R,K1)*\sum_{i=0}^K[C(K1,i)*C(K2,i+R_x)]\)

考虑后半部分 :
\(\sum_{i=0}^K[C(K1,i)*C(K2,i+R_x)]\)
\(= \sum_{i=0}^K[C(K1,K1-i)*C(K2,i+R_x)]\)
\(= \sum_{i=0}^{K1+R_x}[C(K1,K1-i)*C(K2,i+R_x)]\)

由范德蒙德卷积 : \(\sum_{i=0}^{k}[C(n,i)*C(m,k-i)] =C(n+m,k)\)

可得 后半部分 = \(C(R,K1+R_x)\)
所以 \(Ans = C(R,K1)*C(R,K1+R_x)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 998244353, Mx = 2e5;
ll x, y, R, T;
ll fact[Mx * 2 + 7];
template<typename T> void read(T &x) {
    bool f = false; x = 0;
    char ch = getchar();
    while (ch<'0' || ch>'9') {if (ch == '-') f = true; ch = getchar();}
    while (ch>='0' && ch<='9') x = x * 10 + ch - '0', ch = getchar();
    if (f) x = -x;
}
inline ll inv(ll b) {
    ll p = mod - 2, res = 1;
    for (; p; b = b * b % mod, p /= 2) {
        if (p & 1) res = res * b % mod;
    }
    return res;
}
inline void init() {
    fact[0] = 1;
    for (ll i = 1; i <= Mx * 2 + 1; i++) {
        fact[i] = fact[i-1] * i % mod;
    }
}
inline ll C(ll n, ll m) {return fact[n] * inv(fact[m]) % mod * inv(fact[n-m]) % mod;}
int main() {
    init(), read(T);
    while (T--) {
        read(x), read(y), read(R);
        if (x < 0) x = -x;
        if (y < 0) y = -y;
        if ((x + y > R) || ((R - x - y) % 2 != 0)) puts("0");
        else {
            // puts("Nice");
            printf("%lld\n", C(R,(R - x - y) / 2) * C(R,(R + x - y) / 2) % mod);
        }
    }
    return 0;
}
posted @ 2019-10-11 22:15  Refaint  阅读(290)  评论(0)    收藏  举报