Problem B. Black and White
题目大意:有一个(n) ( imes) (m)的网格,网格之中的格子有黑白两种颜色。
被(0,0),(0,1),(1,0),(1,1)包围的格子是白色,一个格子周围的四个格子的颜色与其都不相同。
现要从(0,0)走到(n,m),每次只能向上或向右走。
给定(k),求满足条件的路径数量,使得这条路径左边的白格子数-黑格子数=(k)。
多组数据。
(n,m,|w| leq 1e5),(T leq 100)
题解:
设当前白格子数-黑格子数为(w)。
发现每次如果只走一步,我们没法判断当前的(w)的变化量。那么考虑走两步。
如果每次都走两步的话,那无非就四种情况:
1.(
ightarrow
ightarrow)
2.(uparrow uparrow)
3.(uparrow
ightarrow)
4.(
ightarrow uparrow)
前两种情况对(w)无影响,而3,4这两种情况可能会对(w)造成影响。
考虑枚举3,4操作的总次数(p),以及4操作的次数(q)。
通过打表,可以发现一个式子:
[lfloor frac{p+1}{2}
floor - q = k
]
由此,我们只需要枚举(p),就能得到合法的(q)了。
现在考虑统计方案数。
设(x=frac{n+m}{2}),那么相当于在(x)次操作中任选(p)次,又在(p)次中任选(q)个。
然后情况1,2的组合,就是在(x-p)次中选(frac{n-p}{2})次。也就是三个组合数。
注意所有这些要除以2的地方都要求是偶数才有意义。
如果(n+m)是奇数,讨论一下第一步怎么走,然后正常算两次就好了。
时间复杂度:(O(Tn))
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define STS system("pause")
template<class D>I read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
const int Mod=998244353,N=100010;
int T,fac[101000],inv[101000];
I add(int &x,int y){(x+=y)>=Mod?x-=Mod:0;}
IN Plus(int x,int y){(x+=y)>=Mod?x-=Mod:0;return x;}
IN Pow(int x,int y=Mod-2){
re res=1;
while(y){
if(y&1)res=(ll)res*x%Mod;
x=(ll)x*x%Mod;
y>>=1;
}
return res;
}
IN C(int x,int y){if(x<y)return 0;return (ll)fac[x]*inv[y]%Mod*inv[x-y]%Mod;}
I init(){
fac[0]=1;
F(i,1,N)fac[i]=(ll)fac[i-1]*i%Mod;
inv[N]=Pow(fac[N]);
FOR(i,N-1,0)inv[i]=(ll)inv[i+1]*(i+1)%Mod;
}
IN solve(int n,int m,int k){
if(!n||!m)return k==0?1:0;
re x=(n+m)>>1,ans=0;
// cout<<n<<" "<<m<<" "<<k<<" "<<x<<endl;
for(re p=0,q;p<=x;p++){
q=((p+1)>>1)-k;
if(q<0||q>p||((n-p)&1)||p>n)continue;
// cout<<"!"<<p<<" "<<q<<endl;
add(ans,(ll)C(x,p)*C(p,q)%Mod*C(x-p,(n-p)>>1)%Mod);
}
return ans;
}
int n,m,k;
int main(){
read(T);init();
while(T--){
read(n);read(m);read(k);
if(!((n+m)&1))printf("%d
",solve(n,m,k));
else printf("%d
",Plus(solve(n-1,m,-k),solve(n,m-1,(n&1)-k)));
}
return 0;
}
/*
5
1 1 0
1 1 -1
2 2 1
2 2 0
4 4 1
*/