2020牛客寒假算法基础集训营4 J 二维跑步
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=43035417
假设有i步选择不动,就有n-i步移动
假设其中又有a步选择往右移,就有n-i-a步左移
所以-m<=a-(n-i-a)<=m
所以(n-m-i)/2<=a<=min{ n-i,(n+m-i)/2 }
令g(i)=Σ C(n-i,a)(3^a)(2^(n-i-a))
答案=Σ C(n,i)g[i]
考虑如何递推求出g[i]
令f(n,m)=C(n,m)(3^m)(2^(n-m))
则3f(n-1,m-1)+2f(n-1,m)=f(n,m)
假设n=8,m=3
g[0]= f(8,3)+ f(8,4)+ f(8,5)
= 3f(7,2)+5f(7,3)+5f(7,4)+2f(7,5)
g[1]= f(7,2)+ f(7,3)+ f(7,4)+ f(7,5)
=3f(6,1)+5f(6,2)+5f(6,3)+5f(6,4)+2f(6,5)
g[2]= f(6,2)+ f(6,3)+ f(6,4)
=3f(5,1)+5f(5,2)+5f(5,3)+2f(5,4)
g[3]= f(5,1)+ f(5,2)+ f(5,3)+ f(5,4)
可以发现,如果已知g[i],那么将g[i]乘5,然后在搞一搞头尾就可以
)#include<cstdio> #include<algorithm> using namespace std; #define N 3000001 const int mod=998244353; typedef long long LL; int g[N]; int pow2[N],pow3[N],fac[N],inv[N]; int C(int n,int m) { return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod; } int f(int n,int m) { return 1ll*C(n,m)*pow3[m]%mod*pow2[n-m]%mod; } int pow(int n,int m) { int s=1; for(;m;m>>=1,n=1ll*n*n%mod) if(m&1) s=1ll*s*n%mod; return s; } int main() { int n,m; scanf("%d%d",&n,&m); pow2[0]=1; pow3[0]=1; fac[0]=1; inv[0]=1; for(int i=1;i<N;++i) { pow2[i]=pow2[i-1]*2%mod; pow3[i]=1ll*pow3[i-1]*3%mod; fac[i]=1ll*fac[i-1]*i%mod; inv[i]=pow(fac[i],mod-2); } int l=0,r=0,nl,nr,ans=1; for(int i=n;i>=0;--i) { nl=max(0,n-m-i+1>>1); nr=min(n-i,m+n-i>>1); if(nl>l) ans=(ans-f(n-i,l++)+mod)%mod; while(nr>r) ans=(ans+f(n-i,++r))%mod; g[i]=ans; ans=5ll*ans%mod; if(nl>=1) ans=(ans+3ll*f(n-i,nl-1)%mod)%mod; ans=(ans-3ll*f(n-i,nr)%mod+mod)%mod; } ans=0; for(int i=0;i<=n;++i) ans=(ans+1ll*C(n,i)*g[i]%mod)%mod; printf("%d",ans); return 0; }