我们先默认第一头牛是 John 的,另一种情况本质相同,最后答案乘上 \(2\) 就可以了。
先说结论:我们将相邻两头牛配对,那么最终答案即满足至少一对牛间隔了奇数个空位的方案数。证明很简单,分 \(3\) 种情况讨论:
- 每对牛间都间隔了奇数个空位。那么 John 开始时让所有牛往右行动,在 Nhoj 行动后,John 只需要保证 Nhoj 行动的牛对应的 John 那头牛也行动,方向向右,这样就能保证轮到 John 时每队牛都间隔奇数个空位,并且不会出现游戏无法终止的情况。然后最后当每对牛都间隔为 \(0\) 时,轮到 Nhoj 行动,John 胜。
- 有些对牛间隔了奇数个空位,还有些隔了偶数个空位。那么 John 开始时选取所有奇数个空位的牛对里的牛行动,这样,如果 Nhoj 移动了奇数个空位的牛对里的牛,同第一种情况,如果移动了隔了偶数个空位牛对里的牛,John 不对对应的牛做任何操作,这样下一轮到他的时候就会变成第一种情况。
- 每对牛间都间隔了偶数个空位。John 先手必须行动,那么就会转化为上面的两种情况,Nhoj 必胜。
算答案我们考虑容斥,用总方案减去每对牛间都间隔了偶数个空位的方案,前者即为 \(\binom{l}{2n}\),后者枚举所有牛对间一共隔了 \(i\) 个空位,简单组合计数得到 \(\binom{l-i-n}{n}\binom{i/2+n-1}{n-1}\)。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long LL;
typedef pair<LL,int>pli;
const int N=2e6+10,MOD=998244353;
LL fac[N],ifac[N];
int qpow(int a,int b)
{
int res=1;
for(;b;b>>=1)
{
if(b&1)res=1ll*res*a%MOD;
a=1ll*a*a%MOD;
}
return res;
}
void pw(int n)
{
fac[0]=ifac[0]=1;rep(i,1,n)fac[i]=fac[i-1]*i%MOD;
ifac[n]=qpow(fac[n],MOD-2);per(i,n-1,1)ifac[i]=ifac[i+1]*(i+1)%MOD;
}
LL C(int n,int m){return n>=m?fac[n]*ifac[m]%MOD*ifac[n-m]%MOD:0;}
int n,k;
int main()
{
int TOT;scanf("%d",&TOT);
while(TOT--)
{
scanf("%d%d",&n,&k);
pw(2*n+5);
LL ans=C(n,k*2);
for(int i=0;i<=n;i+=2)
{
LL val=C(n-i-k,k)*C(i/2+k-1,k-1)%MOD;
(ans-=val)%=MOD;
}
(ans+=MOD)%=MOD;
printf("%lld\n",ans*2%MOD);
}
return 0;
}
标签:空位,ifac,Farm,题解,int,Game,fac,John,MOD
From: https://www.cnblogs.com/onlycre/p/18107271