【NTT】Gym - 101480 - F - Frightful Formula

题目链接https://codeforces.com/gym/101480/attachments


题意

给出一个矩阵,第一行是数组 t t t,第一列是数组 l l l,其余的值为 F [ i ] [ j ] = a F [ i ] [ j − 1 ] + b F [ i − 1 ] [ j ] + c F[i][j]=aF[i][j-1]+bF[i-1][j]+c F[i][j]=aF[i][j1]+bF[i1][j]+c。问 F [ n ] [ n ] % 1 e 6 + 3 F[n][n]\%1e6+3 F[n][n]%1e6+3的值是多少


题解

对每个 t [ i ] t[i] t[i] l [ i ] l[i] l[i]考虑计算出他们的系数。比如对于 t [ 2 ] t[2] t[2],它在每个位置的系数可以列出来:

t 2 t2 t2 − - − - − - . . . ... ...
C 1 0 a 0 b 1 C_1^0a^0b^1 C10a0b1 C 2 1 a 1 b 1 C_2^1a^1b^1 C21a1b1 C 3 2 a 2 b 1 C_3^2a^2b^1 C32a2b1 C 4 3 a 3 b 1 C_4^3a^3b^1 C43a3b1 . . . ... ...
C 2 0 a 0 b 2 C_2^0a^0b^2 C20a0b2 C 3 1 a 1 b 2 C_3^1a^1b^2 C31a1b2 C 4 2 a 2 b 2 C_4^2a^2b^2 C42a2b2 C 5 3 a 3 b 2 C_5^3a^3b^2 C53a3b2 . . . ... ...
C 3 0 a 0 b 1 C_3^0a^0b^1 C30a0b1 C 4 1 a 1 b 3 C_4^1a^1b^3 C41a1b3 C 5 2 a 2 b 3 C_5^2a^2b^3 C52a2b3 C 6 3 a 3 b 3 C_6^3a^3b^3 C63a3b3 . . . ... ...
C 4 0 a 0 b 1 C_4^0a^0b^1 C40a0b1 C 5 1 a 1 b 4 C_5^1a^1b^4 C51a1b4 C 6 2 a 2 b 4 C_6^2a^2b^4 C62a2b4 C 7 3 a 3 b 4 C_7^3a^3b^4 C73a3b4 . . . ... ...
. . . ... ... . . . ... ... . . . ... ... . . . ... ... . . . ... ...

所以对于每个 t [ i ] t[i] t[i] l [ i ] l[i] l[i]都可以 O ( 1 ) O(1) O(1)的计算出他在 F [ n ] [ n ] F[n][n] F[n][n]上的贡献。
然后就是多加上的 c c c了,一样的稍微列一下就可以发现它是帕斯卡矩阵的前缀和,也就是 ∑ i = 0 n − 2 ∑ j = 0 n − 2 C i + j i a i b j \sum{_{i=0}^{n-2}}\sum{_{j=0}^{n-2}}C{_{i+j}^{i}}a^ib^j i=0n2j=0n2Ci+jiaibj,比上面的表多了第一行,然后是求整个表的和。

关于这个有一些能够 O ( n ) O(n) O(n)的神仙做法,我这里写的是题解的 N T T NTT NTT做法
把式子变换一下即可:
∑ i = 0 n − 2 ∑ j = 0 n − 2 C i + j i a i b j \sum{_{i=0}^{n-2}}\sum{_{j=0}^{n-2}}C{_{i+j}^{i}}a^ib^j i=0n2j=0n2Ci+jiaibj
= ∑ i = 0 n − 2 ∑ j = 0 n − 2 ( i + j ) ! i ! j ! =\sum_{i=0}^{n-2}\sum_{j=0}^{n-2}\frac{(i+j)!}{i!j!} =i=0n2j=0n2i!j!(i+j)!
= ∑ i = 0 n − 2 ∑ j = 0 n − 2 ( i + j ) ! a i i ! b j j ! =\sum_{i=0}^{n-2}\sum_{j=0}^{n-2}(i+j)!\frac{a^i}{i!}\frac{b^j}{j!} =i=0n2j=0n2(i+j)!i!aij!bj
= ∑ i = 0 n − 2 ∑ j = 0 n − 2 f ( i + j ) g ( i ) h ( j ) =\sum_{i=0}^{n-2}\sum_{j=0}^{n-2}f(i+j)g(i)h(j) =i=0n2j=0n2f(i+j)g(i)h(j)
= ∑ k = 0 2 n − 4 f ( k ) ( g ∗ h ( k ) ) =\sum_{k=0}^{2n-4}f(k)(g*h(k)) =k=02n4f(k)(gh(k))
题目给出来的模数 1 e 6 + 3 1e6+3 1e6+3刚好等于 500001 ∗ 2 + 1 500001*2+1 5000012+1,所以可以直接套上 N T T NTT NTT去求。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<ll,int> piir;
const ll N=4e6+7;
const ll inf=1e18;
const ll mod=1e6+3;
const db pi=acos(-1);
ll g[N],h[N];
namespace NTT
{
    typedef long long ll;
    const ll MOD=1945555039024054273LL;
    const ll g=5;
	ll mul(ll x,ll y){
    	return (x*y-(ll)(x/(long double)MOD*y+1e-6)*MOD+MOD)%MOD;
	}
    ll qpow(ll a,ll k){
        ll res=1LL;
        while(k>0){
            if(k&1)res=mul(res,a);
            a=mul(a,a);
            k>>=1;
        }
        return res;
    }
    void change(ll y[],int len){
        for(int i=1,j=len/2;i<len-1;i++){
            if(i<j)swap(y[i],y[j]);
            int k=len/2;
            while(j>=k){
                j-=k;
                k/=2;
            }
            if(j<k)j+=k;
        }
    }
    void ntt(ll y[],int len,int on){
        change(y,len);
        for(int h=2;h<=len;h<<=1){
            ll wn=qpow(g,(MOD-1)/h);
            if(on==-1)wn=qpow(wn,MOD-2);
            for(int j=0;j<len;j+=h){
                ll w=1LL;
                for(int k=j;k<j+h/2;k++){
                    ll u=y[k];
                    ll t=mul(w,y[k+h/2]);
                    y[k]=(u+t)%MOD;
                    y[k+h/2]=(u-t+MOD)%MOD;
                    w=mul(w,wn);
                }
            }
        }
        if(on==-1){
            ll t=qpow(len,MOD-2);
            for(int i=0;i<len;i++)
                y[i]=mul(y[i],t);
        }
    }
    void cal(ll x1[],ll x2[],ll tot){
        int len=1;
        while(len<2*tot)len<<=1;
        ntt(x1,len,1);
        ntt(x2,len,1);
        for(int i=0;i<len;i++)
            x1[i]=mul(x1[i],x2[i]);
        ntt(x1,len,-1);
    }
}

ll qpow(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        b>>=1;a=a*a%mod;
    }
    return res;
}

ll n,a,b,c;
ll l[N],t[N];
ll fac[N],iv[N];
ll comb(ll n,ll m){return fac[n]*iv[n-m]%mod*iv[m]%mod;}
int main()
{
    fac[0]=1;
    for(ll i=1;i<N;i++) fac[i]=(fac[i-1]*i)%mod;
    for(ll i=0;i<N;i++) iv[i]=qpow(fac[i],mod-2);
    scanf("%lld%lld%lld%lld",&n,&a,&b,&c);
    for(int i=1;i<=n;i++){
        scanf("%lld",&l[i]);
    }
    for(int i=1;i<=n;i++){
        scanf("%lld",&t[i]);
    }
    ll ans=0;
    for(int i=2;i<=n;i++){
        ans=(ans+t[i]*comb(2*n-i-2,n-i)%mod*qpow(a,n-i)%mod*qpow(b,n-1)%mod)%mod;
        ans=(ans+l[i]*comb(2*n-i-2,n-i)%mod*qpow(a,n-1)%mod*qpow(b,n-i)%mod)%mod;
    }
    for(ll i=0;i<=n-2;i++){
        g[i]=qpow(a,i)*iv[i]%mod;
        h[i]=qpow(b,i)*iv[i]%mod;
    }
    NTT::cal(g,h,n-1);
    for(ll i=0;i<=2*n-4;i++){
        g[i]%=mod;
        ans=(ans+c*fac[i]%mod*g[i]%mod)%mod;
    }
    printf("%lld\n",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值