题目描述
解题思路
发现自己还是不会卷积。
考虑暴力的递推式:f[i][j]=(p∗f[i−1][j]+q∗f[i][j−1]+(p∗α+q∗β)f[i][j]=(p∗f[i−1][j]+q∗f[i][j−1]+(p∗α+q∗β),边界是f[0][j]=b[j]和f[i][0]=a[i]f[0][j]=b[j]和f[i][0]=a[i],我们计inc=(p∗α+q∗β)inc=(p∗α+q∗β),那么,我们直接考虑一个f[i][j]f[i][j]的值,它是由许多位置的inc和a[i]和b[j]贡献过来的,然后他对答案的贡献还要乘上h的幂。我们分情况考虑。
对于inc:
我们枚举一个位置(x-i,y-j)对(x,y)的贡献
f[x][y]=∑i=0..x−1∑j=0..y−1Cii+j∗inc∗pi∗qjf[x][y]=∑i=0..x−1∑j=0..y−1Ci+ji∗inc∗pi∗qj
对答案的贡献:∑i=0..x−1∑j=0..y−1Cii+j∗inc∗pi∗qj∗h(n+1)x∗hy∑i=0..x−1∑j=0..y−1Ci+ji∗inc∗pi∗qj∗h(n+1)x∗hy
所有f对答案的贡献
∑x=1..n∑y=1..n∑i=0..x−1∑j=0..y−1Cii+j∗inc∗pi∗qj∗h(n+1)x∗hy∑x=1..n∑y=1..n∑i=0..x−1∑j=0..y−1Ci+ji∗inc∗pi∗qj∗h(n+1)x∗hy
∑i=0..n−1∑j=0..n−1Cii+j∗inc∗pi∗qj∗∑x=i+1..n∑y=j+1..nh(n+1)x∗hy∑i=0..n−1∑j=0..n−1Ci+ji∗inc∗pi∗qj∗∑x=i+1..n∑y=j+1..nh(n+1)x∗hy
∑i=0..n−1∑j=0..n−1Cii+j∗inc∗pi∗qj∗∑x=i+1..nh(n+1)x∑y=j+1..n∗hy∑i=0..n−1∑j=0..n−1Ci+ji∗inc∗pi∗qj∗∑x=i+1..nh(n+1)x∑y=j+1..n∗hy
∑i=0..n−1∑j=0..n−1(i+j)!i!j!∗inc∗pi∗qj∗h(n+1)(i+1) (1−h(n+1)(n−i) )1−hn+1∗hj+1 (1−hn−j )1−h∑i=0..n−1∑j=0..n−1(i+j)!i!j!∗inc∗pi∗qj∗h(n+1)(i+1) (1−h(n+1)(n−i) )1−hn+1∗hj+1 (1−hn−j )1−h
我们先令除了组合数的部分的含有i的项和含有j的项分别记为fa[i],fb[j]fa[i],fb[j],那么原式等于
inc∗∑i=0..n−1∑j=0..n−1(i+j)!∗fa[i]∗fb[j]inc∗∑i=0..n−1∑j=0..n−1(i+j)!∗fa[i]∗fb[j]
这个用ntt就可以优化了。
具体的,设F[n]=∑i=0..nfa[i]∗fb[n−i]F[n]=∑i=0..nfa[i]∗fb[n−i],算出F[]然后F[i]∗=inc∗i!F[i]∗=inc∗i!即可,答案贡献就把每一项算进去即可。
对于a[]:
考虑一个位置(x,0)对所有位置的贡献,注意不能给第0列贡献。
∑x=1..nax∑i=0..n∑j=1..nCj−1i+j−1piqjh(n+1)(x+i)+j∑x=1..nax∑i=0..n∑j=1..nCi+j−1j−1piqjh(n+1)(x+i)+j
∑x=1..naxh(n+1)x∑i=0..n∑j=1..n(i+j−1)!i!(j−1)!piqjh(n+1)ihj∑x=1..naxh(n+1)x∑i=0..n∑j=1..n(i+j−1)!i!(j−1)!piqjh(n+1)ihj
∑x=1..naxh(n+1)x∑i=0..n(ph(n+1) )ii!∑j=1..n(qh)j(j−1)!∗(i+j−1)!∑x=1..naxh(n+1)x∑i=0..n(ph(n+1) )ii!∑j=1..n(qh)j(j−1)!∗(i+j−1)!
设f[i]=(ph(n+1) )ii!∑j=1..n(qh)j(j−1)!∗(i+j−1)!f[i]=(ph(n+1) )ii!∑j=1..n(qh)j(j−1)!∗(i+j−1)!,那么一个位置x的贡献就是f的一个前缀和。
考虑如何算f。
设G[i]=∑j=1..n(qh)j(j−1)!∗(i+j−1)!G[i]=∑j=1..n(qh)j(j−1)!∗(i+j−1)!
转化为如何快速求出每个g的值。
设fac[i]=i!,g[j]=(qh)j(j−1)!fac[i]=i!,g[j]=(qh)j(j−1)!
那么G[i]=∑j=1..ng[j]∗fac[i+j−1]G[i]=∑j=1..ng[j]∗fac[i+j−1]
我们发现他们的下标不满足卷积形式,下标加起来是i+2*j-1的,那么考虑把g[]变换一下,使得下标和中的变量只含有i这一项。
g′[n−j+1]=g[j]g′[n−j+1]=g[j]
那么G[i]=∑j=1..ng[n−j+1]∗fac[i+j−1]G[i]=∑j=1..ng[n−j+1]∗fac[i+j−1],发现下标和恰好为n+i,那么有G[i−n]=G′[i]=∑j=0..ig[j]∗fac[i−j]G[i−n]=G′[i]=∑j=0..ig[j]∗fac[i−j],那么我们把G′G′卷积出来,就可以得到G了。
此时我们就可以算出f,然后前缀和一下,枚举x,计算贡献。
此外,f(x,0)位置本身的贡献也要记进去。
对于b[]
和a[]是几乎一样的,只需要把phn+1和qhphn+1和qh交换一下,把a[]和b[]交换一下,就完全一样了。
我怎么搞了3h啊…
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
//开 O2!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
typedef long long ll;
typedef long long LL;
typedef double db;
const int N=1005+5,mo=998244353;
int ksm(int x,int y)
{
int ret=1;
while (y)
{
if (y&1) ret=1ll*ret*x%mo;
y>>=1;
x=1ll*x*x%mo;
}
return ret;
}
int n,h,alp,bet,p1,p2,q1,q2,p,q,inc,f[N][N],i,j,ph,ans;
int main()
{
freopen("dream.in","r",stdin);
// freopen("dream.out","w",stdout);
scanf("%d %d %d %d",&n,&h,&alp,&bet);
scanf("%d %d %d %d",&p1,&p2,&q1,&q2);
p=1ll*p1*ksm(p2,mo-2)%mo;
q=1ll*q1*ksm(q2,mo-2)%mo;
fo(i,1,n) scanf("%d",f[i]+0);
fo(i,1,n) scanf("%d",f[0]+i);
inc=(1ll*p*alp+1ll*q*bet)%mo;
fo(i,1,n) fo(j,1,n)
f[i][j]=(1ll*p*f[i-1][j]+1ll*q*f[i][j-1]+inc)%mo;
ph=1;
fo(i,0,n) fo(j,0,n)
{
ans=(ans+1ll*f[i][j]*ph)%mo;
ph=1ll*ph*h%mo;
}
printf("%d\n",ans);
}