【Codeforces 659G】Fence Divercity
如果考虑切去的部分的话,由于切去部分的形状比较复杂,统计起来比较困难,而切去后剩下的部分形状是很清楚的,所以考虑切去后的剩下部分。
设\(ans_{i,j}\)表示切去从第i列到第j列围栏顶端的块的方案数,显然\[ans_{i,j} = \prod_{k=i+1}^{j-1} {min(h_{k-1},h_k,h_{k+1})} \cdot min(h_i,h_{i+1}) \cdot min(h_{j-1},h_j))\]
从\(ans_{i,j}\)推到\(ans_{i,j+1}\),得\[ans_{i,j+1}=ans_{i,j} \cdot \frac{min(h_j,h_{j+1})}{min(h_j,h_{j-1})} \cdot min(h_{j-1},h_j,h_{j+1})\]
容易发现,向右拓展时答案不受该位置左边距离2以上的数影响。
设\[sum_i = \sum_{j=1}^{i-1}{ans_{j,i}}\]
然后
显然然后\(O(n)\)一遍扫过去就好了,中途把答案加上去。
这么做是需要用到乘法逆元的,但事实上这里并不需要。
设\[c_i=\frac{sum_i}{\min\{h_i,h_{i-1}\}}\]
那么就有\[c_i=c_{i-1} \cdot \min\{h_{i-2},h_{i-1},h_i\} + \min\{h_{i-1},h_i\} \]
然后还是\(O(n)\)扫一遍,统计答案就好了。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn=1000010,p=1e9+7;
LL h[maxn];
int n;
LL sum,ans;
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%I64d",&h[i]),h[i]--;
if (n==1) {printf("%d\n",h[1]);return 0;}
sum=min(h[1],h[2])%p;
ans=(h[1]+h[2]+sum*sum)%p;
for (int i=3;i<=n;i++)
{
LL x=min(h[i-1],h[i]);
sum=(sum*min(h[i-2],x)%p+x)%p;
ans=(ans+sum*x+h[i])%p;
}
printf("%I64d\n",ans);
return 0;
}
评论 (0)