[JZOJ5740] 幻想世界

本文探讨了一种涉及多项式卷积的复杂问题,并通过NTT优化递推式的方法进行解决。介绍了如何处理边界条件、如何分解问题并利用组合数学进行优化计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

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

解题思路

发现自己还是不会卷积。
考虑暴力的递推式: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β)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..x1j=0..y1Cii+jincpiqjf[x][y]=∑i=0..x−1∑j=0..y−1Ci+ji∗inc∗pi∗qj
对答案的贡献:i=0..x1j=0..y1Cii+jincpiqjh(n+1)xhy∑i=0..x−1∑j=0..y−1Ci+ji∗inc∗pi∗qj∗h(n+1)x∗hy
所有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−1Ci+ji∗inc∗pi∗qj∗h(n+1)x∗hy
i=0..n1j=0..n1Cii+jincpiqjx=i+1..ny=j+1..nh(n+1)xhy∑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..n1j=0..n1Cii+jincpiqjx=i+1..nh(n+1)xy=j+1..nhy∑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..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!∗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],那么原式等于
inci=0..n1j=0..n1(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[ni]F[n]=∑i=0..nfa[i]∗fb[n−i],算出F[]然后F[i]=inci!F[i]∗=inc∗i!即可,答案贡献就把每一项算进去即可。

对于a[]:

考虑一个位置(x,0)对所有位置的贡献,注意不能给第0列贡献。
x=1..naxi=0..nj=1..nCj1i+j1piqjh(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)xi=0..nj=1..n(i+j1)!i!(j1)!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)xi=0..n(ph(n+1)  )ii!j=1..n(qh)j(j1)!(i+j1)!∑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(j1)!(i+j1)!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(j1)!(i+j1)!G[i]=∑j=1..n(qh)j(j−1)!∗(i+j−1)!
转化为如何快速求出每个g的值。
fac[i]=i!,g[j]=(qh)j(j1)!fac[i]=i!,g[j]=(qh)j(j−1)!
那么G[i]=j=1..ng[j]fac[i+j1]G[i]=∑j=1..ng[j]∗fac[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..ng[n−j+1]∗fac[i+j−1],发现下标和恰好为n+i,那么有G[in]=G[i]=j=0..ig[j]fac[ij]G[i−n]=G′[i]=∑j=0..ig[j]∗fac[i−j],那么我们把GG′卷积出来,就可以得到G了。
此时我们就可以算出f,然后前缀和一下,枚举x,计算贡献。
此外,f(x,0)位置本身的贡献也要记进去。

对于b[]

和a[]是几乎一样的,只需要把phn+1qhphn+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);
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值