因为保证了
,看起来就是一个进制数一样的东西。形象地理解问题就是可以把第
位的
分配给第
位变成
,求一共有多少种分配方法。
那么我们设
表示假设第
位上是
(
位都是
),有多少种分配方案,要求的就是
。通过枚举分给下一位多少,就有
因为 ,那么 就是一个关于 的 次多项式。我们考虑已知 来推 。
通过二项式定理把 次方展开,然后把 相同的项合并到一起去(可以发现对于相同的 , 的系数都相同),并求出这些系数 ,就是 。通过斯特林数预处理出自然数幂和的系数,直接乘出来即可。
复杂度 。
代码:
#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;
}