[联合集训6-11] 数数题 多项式+自然数幂和

因为保证了 B i < A i + 1 ,看起来就是一个进制数一样的东西。形象地理解问题就是可以把第 i 位的 1 分配给第 i 1 位变成 A i ,求一共有多少种分配方法。
那么我们设 f t ( n ) 表示假设第 t 位上是 n i = 1.. t 1 位都是 B i ),有多少种分配方案,要求的就是 f N ( B N ) 。通过枚举分给下一位多少,就有

f t ( n ) = i = 0 n f t 1 ( i A t + B t 1 )

因为 f 1 ( n ) = 1 ,那么 f t ( n ) 就是一个关于 n t 1 次多项式。我们考虑已知 f t 1 来推 f t
f t 1 ( n ) = k = 0 t 2 a k n k f t ( n ) = k = 0 t 2 a k i = 0 n ( i A t + B t 1 ) k

通过二项式定理把 k 次方展开,然后把 k 相同的项合并到一起去(可以发现对于相同的 k i k 的系数都相同),并求出这些系数 c k ,就是 f t ( n ) = k = 0 t 2 c k i = 0 n i k 。通过斯特林数预处理出自然数幂和的系数,直接乘出来即可。
复杂度 O ( n 3 )

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 35
#define ll long long
#define up(x,y) (x=(x+(y))%mod)
#define inv(x) ksm(x,mod-2)
using namespace std;
const int mod=323232323;
int n;
ll A[N],B[N],C[N][N],S[N][N];
ll ksm(ll a,ll b)
{
    ll r=1;
    for(;b;b>>=1,a=a*a%mod)
        if(b&1) r=r*a%mod;
    return r;
}
struct ploy
{
    int deg;
    ll a[N];
    ploy(){deg=0;memset(a,0,sizeof(a));}
    ploy operator *(ploy b)
    {
        ploy re;re.deg=deg+b.deg;
        for(int i=0;i<=deg;i++)
            for(int j=0;j<=b.deg;j++)
                up(re.a[i+j],a[i]*b.a[j]);
        return re;      
    } 
    ploy operator +(ploy b)
    {
        ploy re;re.deg=max(deg,b.deg);
        for(int i=0;i<=re.deg;i++)
            up(re.a[i],a[i]+b.a[i]);
        return re;  
    }
    ploy operator *(ll d)
    {
        ploy re;re.deg=deg;
        for(int i=0;i<=re.deg;i++)
            re.a[i]=a[i]*d%mod;
        return re;  
    }
    ll qry(ll x)
    {
        ll re=0;
        for(int i=0;i<=deg;i++)
            up(re,a[i]*ksm(x,i));
        return re;  
    }
}dpow[N],spow[N],f[N];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&A[i]);
    for(int i=1;i<=n;i++)
        scanf("%lld",&B[i]);
    C[0][0]=1;
    for(int i=1;i<=n;C[i][0]=1,i++)
        for(int j=1;j<=i;j++)   
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    S[0][0]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=i;j++)
            S[i][j]=(S[i-1][j-1]+S[i-1][j]*j)%mod;  
    dpow[0].a[0]=1;
    ploy now;
    now.deg=1;
    now.a[0]=mod+1;now.a[1]=1;
    for(int i=1;i<=n;i++)
        dpow[i]=dpow[i-1]*now,now.a[0]--;
    for(int k=0;k<n;k++)
        for(int j=0;j<=k;j++)
            spow[k]=spow[k]+dpow[j+1]*(S[k][j]*inv(j+1)%mod);

    f[1].a[0]=1;
    for(int t=2;t<=n;t++)
    {
        ploy tmp;f[t].deg=t-1;  
        for(int k=0;k<t-1;k++)      
            for(int j=0;j<=k;j++)
                up(tmp.a[j],C[k][j]*ksm(A[t],j)%mod*ksm(B[t-1],k-j)%mod*f[t-1].a[k]);
        for(int k=0;k<t-1;k++)
            f[t]=f[t]+spow[k]*tmp.a[k];     
    }
    printf("%lld",f[n].qry(B[n]));
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dofypxy/article/details/80698119