[JZOJ5740] 幻想世界

题目描述

这里写图片描述
这里写图片描述

解题思路

发现自己还是不会卷积。
考虑暴力的递推式: f[i][j]=(pf[i1][j]+qf[i][j1]+(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β) i n c = ( 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..x1j=0..y1Cii+jincpiqj f [ x ] [ y ] = ∑ i = 0.. x − 1 ∑ j = 0.. y − 1 C i + j i ∗ i n c ∗ p i ∗ q j
对答案的贡献: i=0..x1j=0..y1Cii+jincpiqjh(n+1)xhy ∑ i = 0.. x − 1 ∑ j = 0.. y − 1 C i + j i ∗ i n c ∗ p i ∗ q j ∗ h ( n + 1 ) x ∗ h y
所有f对答案的贡献
x=1..ny=1..ni=0..x1j=0..y1Cii+jincpiqjh(n+1)xhy ∑ x = 1.. n ∑ y = 1.. n ∑ i = 0.. x − 1 ∑ j = 0.. y − 1 C i + j i ∗ i n c ∗ p i ∗ q j ∗ h ( n + 1 ) x ∗ h y
i=0..n1j=0..n1Cii+jincpiqjx=i+1..ny=j+1..nh(n+1)xhy ∑ i = 0.. n − 1 ∑ j = 0.. n − 1 C i + j i ∗ i n c ∗ p i ∗ q j ∗ ∑ x = i + 1.. n ∑ y = j + 1.. n h ( n + 1 ) x ∗ h y
i=0..n1j=0..n1Cii+jincpiqjx=i+1..nh(n+1)xy=j+1..nhy ∑ i = 0.. n − 1 ∑ j = 0.. n − 1 C i + j i ∗ i n c ∗ p i ∗ q j ∗ ∑ x = i + 1.. n h ( n + 1 ) x ∑ y = j + 1.. n ∗ h y
i=0..n1j=0..n1(i+j)!i!j!incpiqjh(n+1)(i+1)    (1h(n+1)(ni)    )1hn+1hj+1 (1hnj )1h ∑ i = 0.. n − 1 ∑ j = 0.. n − 1 ( i + j ) ! i ! j ! ∗ i n c ∗ p i ∗ q j ∗ h ( n + 1 ) ( i + 1 )         ( 1 − h ( n + 1 ) ( n − i )         ) 1 − h n + 1 ∗ h j + 1   ( 1 − h n − j   ) 1 − h
我们先令除了组合数的部分的含有i的项和含有j的项分别记为 fa[i],fb[j] f a [ i ] , f b [ j ] ,那么原式等于
inci=0..n1j=0..n1(i+j)!fa[i]fb[j] i n c ∗ ∑ i = 0.. n − 1 ∑ j = 0.. n − 1 ( i + j ) ! ∗ f a [ i ] ∗ f b [ j ]
这个用ntt就可以优化了。
具体的,设 F[n]=i=0..nfa[i]fb[ni] F [ n ] = ∑ i = 0.. n f a [ i ] ∗ f b [ n − i ] ,算出F[]然后 F[i]=inci! F [ i ] ∗ = i n c ∗ i ! 即可,答案贡献就把每一项算进去即可。

对于a[]:

考虑一个位置(x,0)对所有位置的贡献,注意不能给第0列贡献。
x=1..naxi=0..nj=1..nCj1i+j1piqjh(n+1)(x+i)+j ∑ x = 1.. n a x ∑ i = 0.. n ∑ j = 1.. n C i + j − 1 j − 1 p i q j h ( n + 1 ) ( x + i ) + j
x=1..naxh(n+1)xi=0..nj=1..n(i+j1)!i!(j1)!piqjh(n+1)ihj ∑ x = 1.. n a x h ( n + 1 ) x ∑ i = 0.. n ∑ j = 1.. n ( i + j − 1 ) ! i ! ( j − 1 ) ! p i q j h ( n + 1 ) i h j
x=1..naxh(n+1)xi=0..n(ph(n+1)  )ii!j=1..n(qh)j(j1)!(i+j1)! ∑ x = 1.. n a x h ( n + 1 ) x ∑ i = 0.. n ( p h ( n + 1 )     ) i i ! ∑ j = 1.. n ( q h ) j ( j − 1 ) ! ∗ ( i + j − 1 ) !
f[i]=(ph(n+1)  )ii!j=1..n(qh)j(j1)!(i+j1)! f [ i ] = ( p h ( n + 1 )     ) i i ! ∑ j = 1.. n ( q h ) j ( j − 1 ) ! ∗ ( i + j − 1 ) ! ,那么一个位置x的贡献就是f的一个前缀和。
考虑如何算f。
G[i]=j=1..n(qh)j(j1)!(i+j1)! G [ i ] = ∑ j = 1.. n ( q h ) j ( j − 1 ) ! ∗ ( i + j − 1 ) !
转化为如何快速求出每个g的值。
fac[i]=i!,g[j]=(qh)j(j1)! f a c [ i ] = i ! , g [ j ] = ( q h ) j ( j − 1 ) !
那么 G[i]=j=1..ng[j]fac[i+j1] G [ i ] = ∑ j = 1.. n g [ j ] ∗ f a c [ i + j − 1 ]
我们发现他们的下标不满足卷积形式,下标加起来是i+2*j-1的,那么考虑把g[]变换一下,使得下标和中的变量只含有i这一项。
g[nj+1]=g[j] g ′ [ n − j + 1 ] = g [ j ]
那么 G[i]=j=1..ng[nj+1]fac[i+j1] G [ i ] = ∑ j = 1.. n g [ n − j + 1 ] ∗ f a c [ i + j − 1 ] ,发现下标和恰好为n+i,那么有 G[in]=G[i]=j=0..ig[j]fac[ij] G [ i − n ] = G ′ [ i ] = ∑ j = 0.. i g [ j ] ∗ f a c [ i − j ] ,那么我们把 G G ′ 卷积出来,就可以得到G了。
此时我们就可以算出f,然后前缀和一下,枚举x,计算贡献。
此外,f(x,0)位置本身的贡献也要记进去。

对于b[]

和a[]是几乎一样的,只需要把 phn+1qh p h n + 1 和 q h 交换一下,把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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值