熊神仙的做法好难想到。。。
暴力转移是这样的: d p i , x , y = ∑ d p i − 1 , x − x 0 , y − y 0 ( x 0 + y 0 ≤ a i ) dp_{i,x,y}=∑dp_{i-1,x-x_0,y-y_0}(x_0+y_0\leq a_i) dpi,x,y=∑dpi−1,x−x0,y−y0(x0+y0≤ai)
相当于要对一个等腰 rt 的区域求和。
观察到 d p i , x − 1 , y dp_{i,x-1,y} dpi,x−1,y 的重叠部分:
d
p
i
,
x
,
y
=
d
p
i
,
x
−
1
,
y
−
l
i
n
e
(
x
−
1
,
y
−
m
→
x
−
m
−
1
,
y
)
+
l
i
n
e
(
x
,
y
→
x
,
y
−
m
)
dp_{i,x,y}=dp_{i,x-1,y}-line(_{x-1,y-m}\to _{x-m-1,y})+line(_{x,y}\to_{x,y-m})
dpi,x,y=dpi,x−1,y−line(x−1,y−m→x−m−1,y)+line(x,y→x,y−m)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1e17;
int n,m,s1,s2,s3,sum,a[205];
ll dp[205][205][205],sum1[205][205],sum2[205][205];
void Mod(ll &x,ll y) {
x=(x+y)%mod;
}
ll Sum1(int x,int y,int x0) {
if(y<0) x+=y,y=0;
if(x>=0&&y>=0) {
if(x0>=1&&x+y-x0+1<=s2) return sum1[x][y]-sum1[x0-1][x+y-x0+1];
return sum1[x][y];
}
return 0;
}
ll Sum2(int x,int y,int y0) {
if(x>=0&&y>=0) {
if(y0>=1) return sum2[x][y]-sum2[x][y0-1];
return sum2[x][y];
}
return 0;
}
int main() {
// freopen("data.in","r",stdin);
scanf("%d%d%d%d",&n,&s1,&s2,&s3);
dp[0][0][0]=1;
for(int i=0;i<=s1;i++) {
for(int j=0;j<=s2;j++) {
sum1[i][j]=((i>=1)?sum1[i-1][j+1]:0)+dp[0][i][j];
sum2[i][j]=((j>=1)?sum2[i][j-1]:0)+dp[0][i][j];
}
}
for(int i=1;i<=n;i++) {
scanf("%d",&m),sum+=m;
for(int x=0;x<=s1;x++) {
for(int y=0;y<=s2;y++) {
dp[i][x][y]=(((x>=1)?dp[i][x-1][y]:0)-Sum1(x-1,y-m,x-m-1)+Sum2(x,y,y-m))%mod;
}
}
for(int x=0;x<=s1;x++) {
for(int y=0;y<=s2;y++) {
sum1[x][y]=(((x>=1)?sum1[x-1][y+1]:0)+dp[i][x][y])%mod;
sum2[x][y]=(((y>=1)?sum2[x][y-1]:0)+dp[i][x][y])%mod;
}
}
}
if(sum!=s1+s2+s3) {
printf("0");
}
else {
printf("%lld",(dp[n][s1][s2]+mod)%mod);
}
}