因为保证了
Bi<Ai+1
B
i
<
A
i
+
1
,看起来就是一个进制数一样的东西。形象地理解问题就是可以把第
i
i
位的分配给第
i−1
i
−
1
位变成
Ai
A
i
,求一共有多少种分配方法。
那么我们设
ft(n)
f
t
(
n
)
表示假设第
t
t
位上是(
i=1..t−1
i
=
1..
t
−
1
位都是
Bi
B
i
),有多少种分配方案,要求的就是
fN(BN)
f
N
(
B
N
)
。通过枚举分给下一位多少,就有
因为 f1(n)=1 f 1 ( n ) = 1 ,那么 ft(n) f t ( n ) 就是一个关于 n n 的次多项式。我们考虑已知 ft−1 f t − 1 来推 ft f t 。
通过二项式定理把 k k 次方展开,然后把相同的项合并到一起去(可以发现对于相同的 k k ,的系数都相同),并求出这些系数 ck c k ,就是 ft(n)=∑t−2k=0ck∑ni=0ik f t ( n ) = ∑ k = 0 t − 2 c k ∑ i = 0 n i k 。通过斯特林数预处理出自然数幂和的系数,直接乘出来即可。
复杂度 O(n3) 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;
}