P5014 水の三角(修改版)
P5014 水の三角(修改版)
题意
请求出一个无限大的三角图从 1 号点走到 \(u\) 号点的方案数。
有 \(T\) 组询问。
分析
首先我们查看操作对我们当前位置的影响。
左下:\((1,0)\);右下:\((1,1)\);右:\((0,1)\)。
易得枚举往左下或者右下走的次数是比较方便的。易发现枚举往右下走的次数更好,因为不影响边界。而后若假设枚举了往右下走的次数 \(k\),那么我们显然有左下 \(x-k\) 步,右下 \(k\) 步,右 \(y-k\) 步。则右下走的方案数为 \(C_{x+y-k}^{k}(k∈[0,\min(x,y) ])\)。而后我们此时有:从 \((0,0)\) 走到 \((x-k,y-k)\),每步可以走 \(x\) 或 \(y\),要求过程中 \(y≤x\),求方案数 \(f(k)\)。则我们使用计算卡特兰数模板的方法,我们把不合法的路径都映射到从 \((0,0)\) 走到 \((y-k-1,x-k+1)\) 的路径上。则可由组合数的意义得 \(f(k)=C_{x+y-2k}^{x-k}-C_{x+y-2k}^{x-k+1}\)。则我们可以由乘法原理得总贡献为右下方案数乘上合法其他路径方案数。则有 \(Ans=\sum_{k=0}^{\min(x,y)}C_{x+y-k}^{k}·f_{k}\)。考虑使用快速幂+逆元维护组合数。别忘了处处取模。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m;
const int mod=998244353;
struct node{
int inv[2000090],fac[2000090];
int qpow(int shu,int cifang){
int ans=1;int k=cifang;
while(k){
if(k&1){ans=ans*shu%mod;ans%=mod;shu=shu*shu%mod;shu%=mod;}
else{shu=shu*shu%mod;shu%=mod;}
k>>=1;
}
return ans%mod;
}
void init(int len){
fac[0]=1;
for(int i=1;i<=len;i++) fac[i]=fac[i-1]*i%mod;
inv[len]=qpow(fac[len],mod-2);
for(int i=len;i;i--){
inv[i-1]=inv[i]*(i)%mod;
}
}
int C(int n,int m){
// printf("%d %d\n",n,m);
// printf("%d",fac[n]%mod*inv[m]%mod*inv[n-m]%mod);
return fac[n]%mod*inv[m]%mod*inv[n-m]%mod;
}
}lg_get;
int f(int x,int y,int k){
int ans=lg_get.C(x+y-2*k,x-k)%mod-lg_get.C(x+y-2*k,x-k+1)%mod;
ans+=mod,ans%=mod;
return ans;
}
void solve(){
scanf("%lld",&n);
int a=sqrt(n)-1,k;
while(n-(long long)a*(a-1)/2>a)a++;
k=n-(long long)a*(a-1)/2;
// int x=k,y=a;
int y=k,x=a;
x--,y--;
// printf("%lld %lld\n",x,y);
int ans=0;
for(int kk=0;kk<=min(x,y);kk++){
// printf("%d\n",kk);
int tmp=lg_get.C(x+y-kk,kk)%mod*f(x,y,kk)%mod;
tmp%=mod;
// printf("%lld\n",tmp);
ans+=tmp;
ans%=mod;
}
printf("%lld\n",ans);
}
const int MAXN=1e6+7;
signed main(){
lg_get.init(MAXN*2);
int T;
cin>>T;
while(T--) solve();
}