首先考虑
D
P
DP
DP ,定义状态
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k 表示转移到第
i
i
i 行时,所有第
1
1
1 列的还未转移的数的和为
j
j
j ,所有第
2
2
2 列的还未转移的数的和为
k
k
k 的总方案数。那么可以写出以下转移方程式:
d
p
i
,
j
,
k
=
∑
x
=
0
a
i
∑
y
=
0
a
i
−
x
d
p
i
−
1
,
j
+
x
,
k
+
y
dp_{i,j,k}=\sum_{x=0}^{a_i}\sum_{y=0}^{a_i-x}dp_{i-1,j+x,k+y}
dpi,j,k=x=0∑aiy=0∑ai−xdpi−1,j+x,k+y
若我们将
i
−
1
i-1
i−1 的所有
d
p
dp
dp 值用一张表表示出来,假设
a
=
2
a=2
a=2,那么
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k 的值即为图中三角形部分。
考虑如何优化,我们首先发现
d
p
i
,
j
,
k
dp_{i,j,k}
dpi,j,k 与
d
p
i
,
j
−
1
,
k
dp_{i,j-1,k}
dpi,j−1,k 有一定的重叠部分,从这个地方我们来考虑转移。
再看两者之间所相差的即为
∑
x
=
0
a
i
+
1
d
p
i
−
1
,
j
,
k
+
x
−
∑
x
=
0
a
i
+
1
d
p
i
−
1
,
j
+
a
i
+
1
−
x
,
k
+
x
\sum _{x=0}^{a_i+1}dp_{i-1,j,k+x}-\sum _{x=0}^{a_i+1}dp_{i-1,j+a_i+1-x,k+x}
x=0∑ai+1dpi−1,j,k+x−x=0∑ai+1dpi−1,j+ai+1−x,k+x
这两个式子用前缀和求解即可。
时间复杂度
O
(
n
c
2
)
O(nc^2)
O(nc2)。
代码:
#include<bits/stdc++.h>
using namespace std;
long long n,s1,s2,s3,a[100005],sum,dp[130][130],sum1[130][130],sum2[130][130],mod=1e17;
long long Sum1(int x,int l,int r){
if(r>s2)r=s2;
return sum1[x][r]-(l?sum1[x][l-1]:0);
}
long long Sum2(int a,int b,int c,int d){
if(b>=s2)a+=(b-s2),b=s2;
if(d>=s2)c+=(d-s2),d=s2;
return ((a>s1||a<0||b>s2||b<0||a+b>s1+s2||a+b<0)?0:sum2[a][b])-((c>s1||c<0||d>s2||d<0||c+d>s1+s2||a+b<0)?0:sum2[c][d]);
}
int main(){
scanf("%lld%lld%lld%lld",&n,&s1,&s2,&s3);
for(long long i=1;i<=n;i++){
scanf("%lld",&a[i]);
sum+=a[i];
}
dp[s1][s2]=1;
for(long long j=s1;j>=0;j--){
for(long long l=0;l<=s2;l++){
sum1[j][l]=((l-1)<0?0:sum1[j][l-1])+dp[j][l];
sum2[j][l]=((l-1<0||j+1>s1)?0:sum2[j+1][l-1])+dp[j][l];
sum1[j][l]%=mod;
sum2[j][l]%=mod;
}
}
for(long long i=1;i<=n;i++){
for(long long j=s1;j>=0;j--){
for(long long l=s2;l>=0;l--){
dp[j][l]=dp[j+1][l]+Sum1(j,l,l+a[i]+1)-Sum2(j,l+a[i]+1,j+a[i]+2,l-1);
dp[j][l]%=mod;
}
}
for(long long j=s1;j>=0;j--){
for(long long l=0;l<=s2;l++){
sum1[j][l]=((l-1)<0?0:sum1[j][l-1])+dp[j][l];
sum2[j][l]=((l-1<0||j+1>s1)?0:sum2[j+1][l-1])+dp[j][l];
sum1[j][l]%=mod;
sum2[j][l]%=mod;
}
}
}
if(sum!=s1+s2+s3){
printf("0");
}else{
dp[0][0]+=mod;
dp[0][0]%=mod;
printf("%lld\n",dp[0][0]);
}
return 0;
}