解析:设dp[i][j]为考虑前i个Fence,cut的部分包含第i个Fence,第i个Fence处理后的高度为j的方案数。
则首先 1<=j<h[i]
如果j<h[i-1],dp[i][j] = 1+sigma(dp[i-1][k]), 1<=k<=min(h[i-1]-1,h[i]-1);
反之,dp[i][j] = 1;
得到转移方程后显然不能直接用,因为空间和时间都特别大,但是我们注意到,对于每一个i,我们只需要维护3个前缀和就可以完成方程的转移。
设s[i][j] = dp[i][1]+dp[i][2]+...+dp[i][j],
这样一来,需要维护的j 的值有三个,min(h[i-1]-1,h[i]-1),h[i],min(h[i]-1,h[i+1]-1);
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
long long mod=1e9+7;
long long dp[1000005][3];
int h[1000005];
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)
{
scanf("%d",&h[i]);
}
h[0]=1;
h[n+1]=1;
for(int i=1;i<=n;i++)
{
int a=min(h[i]-1,h[i-1]-1);
int b=h[i];
int c=min(h[i]-1,h[i+1]-1);
dp[i][0] = (dp[i-1][2]+1)*a%mod;
dp[i][1] = (dp[i][0]+b-a-1)%mod;
if(c>=a)
dp[i][2] = (dp[i][0]+c-a)%mod;
else
dp[i][2] = (dp[i-1][2]+1)*c%mod;
}
long long ans=0;
for(int i=1;i<=n;i++)
{
ans=(ans+dp[i][1])%mod;
}
ans=(ans+mod)%mod;
printf("%lld\n",ans);
}
}