Gym 102471B Black and White

Link
只考虑\(2|n+m\)的情况,否则可以通过枚举最后一步怎么走来转化为该种情况。
那么此时我们不妨一次性连续走两步,如果两步都往同一方向走,那么这并不会影响这条路径的权值。
假如说上右走了\(p\)次,右上走了\(q\)次,那么这条路径的权值就是\(\lfloor\frac{p+1}2\rfloor-q\)
那么枚举\(p\)然后求出四种走法的次数再组合数计算方案数即可。

#include<cstdio>
const int N=200007,P=998244353;
int fac[N],ifac[N];
int read(){int x;scanf("%d",&x);return x;}
int C(int n,int m){return m<0||n<m? 0:1ll*fac[n]*ifac[m]%P*ifac[n-m]%P;}
int pow(int a,int b){int r=1;for(;b;b>>=1,a=1ll*a*a%P)if(b&1)r=1ll*a*r%P;return r;}
int f(int n,int m,int k)
{
    int ans=0,x=(n+m)/2;
    for(int i=0;i<=n&&i<=m;++i) if(!(k>(i+1)/2||k<-(i/2)||(n-i)&1||(m-i)&1)) ans=(ans+1ll*C(x,i)*C(i,k+(i/2))%P*C(x-i,(n-i)/2))%P;
    return ans;
}
int main()
{
    fac[0]=1;for(int i=1;i<=100000;++i)fac[i]=1ll*fac[i-1]*i%P;
    ifac[100000]=pow(fac[100000],P-2);for(int i=100000;i;--i) ifac[i-1]=1ll*ifac[i]*i%P;
    for(int t=read(),n,m,k;t;--t) n=read(),m=read(),k=read(),printf("%d\n",(n+m)&1? (f(n-1,m,k+(m&1))+f(n,m-1,k))%P:f(n,m,k));
}

猜你喜欢

转载自www.cnblogs.com/cjoierShiina-Mashiro/p/12905873.html