题目链接: https://codeforces.com/gym/102428/problem/F
题意:
你现在有 m m m 个方块,要搭建一个以 s s s 为底的一个模型,这个模型是不能储水的结构,即不存在一列,其左边和右边的俩均比它高,问你有多少种搭建的方法。
做法:
d p [ i ] [ j ] dp[i][j] dp[i][j] 表示以 i i i 为底的时候,还有 j j j 个方块时的方案数。这个时候 d p [ i ] [ j ] = 1 ∗ d p [ i ] [ j − i ] + 2 ∗ d p [ i − 1 ] [ j − i + 1 ] + 3 ∗ d p [ i − 2 ] [ j − i + 2 ] . . . dp[i][j]=1*dp[i][j-i]+2*dp[i-1][j-i+1]+3*dp[i-2][j-i+2]... dp[i][j]=1∗dp[i][j−i]+2∗dp[i−1][j−i+1]+3∗dp[i−2][j−i+2]... ,这个式子很容易得出,但是在原来我们做的时候,用记忆化搜索对于每一个 d p [ i ] [ j ] dp[i][j] dp[i][j] 均 f o r for for 了一次所有的情况,所以就 T T T 了,这个结构我们可以发现是 可以用两个前缀和来维护的,一个维护 s u m [ i + j ] sum[i+j] sum[i+j] 的前缀和,另一个维护上面那样,所谓前缀和的前缀和。
代码
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=5005;
const int mod=(int)1e9+7;
int n,m;
ll sum[maxn*2],psum[maxn*2],dp[maxn][maxn];
int main() {
scanf("%d%d",&n,&m);
m-=n;
for(int s=1;s<=n;s++){
for(int res=0;res<=m;res++){
psum[res]=(psum[res]+sum[res])%mod;
if(res==0) dp[s][res]=1;
else dp[s][res]=(dp[s][res]+psum[res])%mod;
sum[s+res]=(sum[s+res]+dp[s][res])%mod;
}
}
printf("%lld\n",dp[n][m]);
return 0;
}