神祕題目

Descriptionspa

在一個平面直角座標系中,你站在原點,即(0,0)上。你每次能夠選擇往上下左右中的一個方向走1個單位的距離(不能不走)。問你用k步走到(a,b)的方案數。(只須要k步後在終點便可,不關注途中是否通過終點)code

Inputblog

本題有多組數據。ip

第一行一個整數t,表示數據組數。string

接下來t行,第i+1行包含三個整數ai,bi,ki,表示第i次詢問終點爲(ai,bi),步數爲kiit

Outputio

共t行,每行一個整數,表示答案。class

Sample Inputim

3數據

1 1 1

0 1 2

4 4 10

Sample Output

0

0

2520

HINT

對於100%的數據,1<t≤106,0≤ai,bi≤106,0≤ki≤3*106


Solution

(本題解僅適用於我這種只會暴力推導的蒟蒻選手,請開題就旋轉45°秒題的大佬們出門左轉慢走不送。)

顯然,當a+b<k或k-a-b爲奇數時,沒有符合要求的方案。

從(0,0)到(a,b)至少須要a+b步。

對於剩下的k-a-b步,需知足向左(上)走和向右(下)走的步數相等。

令n=(k-a-b)/2,咱們能夠獲得

$ans=\sum\limits_{i=0}^{n}({{k}\atop{a+2i}})({{a+2i}\atop{i}})({{b+2n-2i}\atop{n-i}})$

$=\sum\limits_{i=0}^{n}\frac{k!}{i!(a+i)!(n-i)!(b+n-i)!}$(注:k-a-2i=a+b+2n-a-2i=b+2n-2i)

接下來是最重要的一步,咱們能夠發現i+(n-i)=n,(a+i)+(b+n-i)=k-n,n+(k-n)=k,因而咱們能夠考慮搞一點事情↓

$k!=\frac{k!*n!*(n-k)!}{n!*(n-k)!}$

代入原式可得

$ans=({{k}\atop{n}})\sum\limits_{i=0}^{n}({{n}\atop{i}})({{k-n}\atop{a+i}})$

彷佛看不出什麼,咱們將$({{k-n}\atop{a+i}})$變爲$({{k-n}\atop{k-n-a-i}})$。

理性分析一下咱們能夠發現,$\sum\limits_{i=0}^{n}({{n}\atop{i}})({{k-n}\atop{k-n-a-i}})$表示的是從k個球中取k-n-a個球的方案數,則$ans=({{k}\atop{n}})({{k}\atop{k-n-a}})$,單次詢問的時間複雜度O(1),總時間複雜度爲O(t)。

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=998244353;
const int len=25000000;
char s[len];int pos=0;
inline int rd(){
    char c=s[pos++];int flag=1,x=0;
    for(;c<'0'||c>'9';c=s[pos++])if(c=='-')flag=-1;
    for(;c>='0'&&c<='9';c=s[pos++])x=x*10+c-'0';
    return x*flag;
}
int fac[3000010]={1},inv[3000010]={1};
int power(int x,int k){
    int res=1,s=x;
    for(;k;k>>=1){
        if(k&1)
            res=(ll)res*s%mod;
        s=(ll)s*s%mod;
    }
    return res;
}
void prepare(){
    for(int i=1;i<=3000000;i++)
        fac[i]=(ll)fac[i-1]*i%mod;
    inv[3000000]=power(fac[3000000],mod-2);
    for(int i=2999999;i;i--)
        inv[i]=(ll)inv[i+1]*(i+1)%mod;
    return;
}
int C(int n,int m){
    return (ll)fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int solve(int a,int b,int k){
    int n=(k-a-b)>>1;
    return (ll)C(k,n)*C(k,k-n-a)%mod;
}
int main(){
    freopen("data_A.in","r",stdin);
    freopen("ans_A.out","w",stdout);
    fread(s,1,len,stdin);
    prepare();
    for(int t=rd();t--;){
        int a=rd(),b=rd(),k=rd();
        if(a+b>k||((k-a-b)&1)){
            puts("0");
            continue;
        }
        printf("%d\n",solve(a,b,k));
    }
    return 0;
}
相關文章
相關標籤/搜索