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;
}

猜你喜欢

转载自www.cnblogs.com/TheRoadToTheGold/p/12335061.html