codeforces div2 346 G Fence Divercity Dp + 计数

/*
    题目描述:在一个类似俄罗斯方块的图中,从最顶部(一定是顶部)拿走连通的一些正方形块,(题目及图片见底部),问一共有多少种拿法。
    
    思路:首先把所有h[k]减1,保证不会掏空;
         设dp1[i]表示如果拿的最后一个方块在第i列,拿法的种数;
         dp2[i]表示如果第i列的高度高于第i+1列,最后一个方块在第i列且最后一个方块的高度小于等于第i+1列高度时的拿法数,
         递推方程见代码,注意边界条件的判断容易出错
*/
#pragma warning(disable:4786)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<cmath>
#include<string>
#include<sstream>
#include<bitset>
#define LL long long
#define FOR(i,f_start,f_end) for(int i=f_start;i<=f_end;++i)
#define mem(a,x) memset(a,x,sizeof(a))
#define lson l,m,x<<1
#define rson m+1,r,x<<1|1
using namespace std;
const LL INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps=1e-6;
const int maxn = 1e6 + 5;
LL dp1[maxn] , dp2[maxn] , h[maxn];
int main()
{
    int n ;
    scanf("%d",&n);
    for(int i = 1 ; i<= n ; i++){
        scanf("%lld",&h[i]);
        --h[i];
    }
    dp1[1] = h[1] % mod;
    if(n >= 2 && h[2] < h[1])
        dp2[1] = h[2] % mod;
    for(int i = 2 ; i<= n ; i++){
        //根据h[i]与h[i - 1]的关系更新h[i]
        if(h[i] >= h[i - 1]){           
            dp1[i] = (dp1[i - 1] * h[i - 1] %mod+ h[i]) % mod;
        }
        else{
            dp1[i] = (dp2[i - 1]*h[i] % mod + h[i]) % mod;
        }
        //当h[i] > h[i + 1](保证dp2[i]有意义的前提下),根据h[i]与h[i - 1]以及h[i + 1]的关系更新dp2[i]
        if(i < n && h[i] > h[i + 1]){
            if(h[i + 1] >= h[i - 1] && h[i] > h[i + 1]){
                dp2[i] = (dp1[i] - (h[i] - h[i + 1]) + mod) % mod;
            }
            else if(h[i + 1] < h[i - 1] && h[i] >= h[i - 1]){
                dp2[i] = (dp1[i] - dp1[i - 1] * (h[i - 1] - h[i + 1]) % mod - (h[i] - h[i + 1]) % mod + mod) % mod;
            }
            else if(h[i + 1] < h[i - 1] && h[i] < h[i - 1]){
                dp2[i] = (dp1[i] - dp2[i - 1] * (h[i] - h[i + 1]) % mod - (h[i] - h[i + 1]) % mod + mod) % mod;
            }
        }
    }
    LL ans = 0;
    for(int i = 1 ; i<= n ; i++){
        ans = (ans + dp1[i]) % mod;
    }
    printf("%lld\n",ans);
    return 0;
}
G. Fence Divercity
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Long ago, Vasily built a good fence at his country house. Vasily calls a fence good, if it is a series of n consecutively fastened vertical boards of centimeter width, the height of each in centimeters is a positive integer. The house owner remembers that the height of thei-th board to the left is hi.

Today Vasily decided to change the design of the fence he had built, by cutting his top connected part so that the fence remained good. The cut part should consist of only the upper parts of the boards, while the adjacent parts must be interconnected (share a non-zero length before cutting out of the fence).

You, as Vasily's curious neighbor, will count the number of possible ways to cut exactly one part as is described above. Two ways to cut a part are called distinct, if for the remaining fences there is such i, that the height of the i-th boards vary.

As Vasily's fence can be very high and long, get the remainder after dividing the required number of ways by 1 000 000 007 (109 + 7).

Input

The first line contains integer n (1 ≤ n ≤ 1 000 000) — the number of boards in Vasily's fence.

The second line contains n space-separated numbers h1, h2, ..., hn (1 ≤ hi ≤ 109), where hi equals the height of the i-th board to the left.

Output

Print the remainder after dividing r by 1 000 000 007, where r is the number of ways to cut exactly one connected part so that the part consisted of the upper parts of the boards and the remaining fence was good.

Examples
input
2
1 1
output
0
input
3
3 4 2
output
13
Note

From the fence from the first example it is impossible to cut exactly one piece so as the remaining fence was good.

All the possible variants of the resulting fence from the second sample look as follows (the grey shows the cut out part):


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值