首先发现
α,β
α
,
β
的贡献和
ak,bk
a
k
,
b
k
的贡献是可以分开计算的,把一个DP状态看成是二维坐标上的一个点,转移就是每次从左边
(x−1,y)
(
x
−
1
,
y
)
或者从下面
(x,y−1)
(
x
,
y
−
1
)
转移。
先考虑计算
α,β
α
,
β
的贡献。
考虑枚举两个点
(x1,y1),(x2,y2)(x1≤x2,y1≤y2)
(
x
1
,
y
1
)
,
(
x
2
,
y
2
)
(
x
1
≤
x
2
,
y
1
≤
y
2
)
,计算转移到
(x1,y1)
(
x
1
,
y
1
)
的那一步对
(x2,y2)
(
x
2
,
y
2
)
的贡献,从两点之间的路径条数入手可以得到:
这样显然无法计算,转换成枚举 i=x2−x1,j=y2−y1 i = x 2 − x 1 , j = y 2 − y 1 ,
拆开组合数,
先把最后的 h h 用等比数列求和求出来,然后换成枚举,然后就可以卷积了,
再考虑计算
ak
a
k
的贡献,
bk
b
k
同理。
对于每一个
ak
a
k
,可以分别计算贡献求和:
组合数里 y−1 y − 1 是因为最后一步必须选择纵坐标 −1 − 1 ,但这样还是无法计算,因为 ak a k 有 n n 个,于是还是考虑枚举差,
其中 a′i=∑nx=i+1ax−ihx(n+1) a i ′ = ∑ x = i + 1 n a x − i h x ( n + 1 ) ,可以先卷积预处理出来。然后像之前一样枚举 i+y i + y 再卷起来就行了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 524290
#define ll long long
#define up(x,y) (x=(x+(y))%mod)
using namespace std;
const int mod=998244353;
const int g=3;
ll ksm(ll a,ll b){ll r=1;for(b=(b+mod-1)%(mod-1);b;b>>=1){if(b&1)r=r*a%mod;a=a*a%mod;}return r;}
ll inv(ll x){return ksm(x,mod-2);}
int n,m,r[N];
ll h,hn,A,B,P,Q,a[N],b[N],ans,fac[N],ifac[N],p[N],q[N],pow_P[N],pow_Q[N],pow_h[N],pow_hn[N],c[N];
void ntt(ll a[],int m,int dft)
{
for(int i=0;i<m;i++)
r[i]=(r[i>>1]>>1)|((i&1)*(m>>1));
for(int i=0;i<m;i++)
if(i<r[i]) swap(a[i],a[r[i]]);
for(int i=1;i<m;i<<=1)
{
ll wn=ksm(g,(mod-1)/(i<<1)*dft);
for(int j=0;j<m;j+=(i<<1))
{
ll wk=1;
for(int k=j;k<j+i;k++)
{
ll x=a[k],y=wk*a[k+i]%mod;
a[k]=(x+y)%mod;a[k+i]=(x-y+mod)%mod;
wk=wk*wn%mod;
}
}
}
if(dft==-1) for(int i=0,t=inv(m);i<m;i++) a[i]=a[i]*t%mod;
}
void multi(ll a[],ll b[],ll c[])
{
ntt(a,m,1);ntt(b,m,1);
for(int i=0;i<m;i++)
c[i]=a[i]*b[i]%mod;
ntt(c,m,-1);
}
int main()
{
scanf("%d%lld%lld%lld",&n,&h,&A,&B);
ll pa,pb,qa,qb;
scanf("%lld%lld%lld%lld",&pa,&pb,&qa,&qb);
P=pa*inv(pb)%mod;Q=qa*inv(qb)%mod;
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
for(int i=1;i<=n;i++)
scanf("%lld",&b[i]);
for(m=1;m<((n+1)<<1);m<<=1);
hn=ksm(h,n+1);
fac[0]=1;
for(int i=1;i<=m;i++)
fac[i]=fac[i-1]*i%mod;
ifac[m]=inv(fac[m]);
for(int i=m-1;i>=0;i--)
ifac[i]=ifac[i+1]*(i+1)%mod;
pow_P[0]=pow_Q[0]=pow_h[0]=pow_hn[0]=1;
for(int i=1;i<=n;i++)
{
pow_P[i]=pow_P[i-1]*P%mod;
pow_Q[i]=pow_Q[i-1]*Q%mod;
pow_h[i]=pow_h[i-1]*h%mod;
pow_hn[i]=pow_hn[i-1]*hn%mod;
}
for(int i=1;i<=n;i++)
up(ans,pow_hn[i]*a[i]+pow_h[i]*b[i]);
//cal A B
ll ih=inv(h-1),ihn=inv(hn-1);
for(int i=0;i<n;i++)
{
p[i]=pow_P[i]*pow_hn[i+1]%mod*(pow_hn[n-i]-1)%mod*ifac[i]%mod*ihn%mod;
q[i]=pow_Q[i]*pow_h[i+1]%mod*(pow_h[n-i]-1)%mod*ifac[i]%mod*ih%mod;
}
multi(p,q,c);
for(int i=0;i<(n<<1);i++)
up(ans,(P*A+Q*B)%mod*fac[i]%mod*c[i]);
//cal a
for(int i=0;i<=(n>>1);i++)
swap(a[i],a[n-i]);
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++)
p[i]=pow_hn[i];
multi(a,p,a);
memset(p,0,sizeof(p));
memset(q,0,sizeof(q));
for(int i=0;i<n;i++)
p[i]=pow_P[i]*ifac[i]%mod*a[i+n]%mod;
for(int i=1;i<=n;i++)
q[i]=pow_Q[i]*pow_h[i]%mod*ifac[i-1]%mod;
multi(p,q,c);
for(int i=1;i<(n<<1);i++)
up(ans,fac[i-1]*c[i]%mod);
//cal b
for(int i=0;i<=(n>>1);i++)
swap(b[i],b[n-i]);
memset(p,0,sizeof(p));
for(int i=1;i<=n;i++)
p[i]=pow_h[i];
multi(b,p,b);
memset(p,0,sizeof(p));
memset(q,0,sizeof(q));
for(int i=1;i<=n;i++)
p[i]=pow_P[i]*pow_hn[i]%mod*ifac[i-1]%mod;
for(int i=0;i<n;i++)
q[i]=pow_Q[i]*ifac[i]%mod*b[i+n]%mod;
multi(p,q,c);
for(int i=1;i<(n<<1);i++)
up(ans,fac[i-1]*c[i]%mod);
printf("%lld",ans);
return 0;
}