题目

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 1048576K,其他语言2097152K
64bit IO Format: %lld

题目描述

Compute 买了台新电脑,他的初始壁纸是自带的风景壁纸,但他更喜欢小姐姐。

现在 CSL 连续 n 天每天给 Compute 一张小姐姐照片,第 i 张的小姐姐对 Compute 有ai的吸引力。Compute 可以选择在这天换上 CSL 当天发给他的壁纸,并至少连续使用ai天。

但我们都知道,每张壁纸的吸引力都会日益衰减,具体来说,当前壁纸每天对他的吸引力都会衰减 1。当衰减到 0 之后,Compute 就有可能换掉它,或者也有可能在之后的某天才换掉它,甚至不换一直用下去。

比如说,在第 1 天,CSL 发了一张吸引力为 2 的小姐姐壁纸给他并且他使用了这张壁纸;那么第 2 天,这张壁纸的吸引力就会减为 1 ,他肯定不会更换壁纸;但到了第 3 天,这张壁纸的吸引力减为 0,他可以选择更换为另一个壁纸或继续使用原来那张壁纸。

Compute 想知道,这 n 天他的桌面壁纸至少出现过两张不同的小姐姐的方案有多少种。

由于这个数可能很大,你只需要输出它对 109+7 取余后的结果即可。

输入描述

第一行有一个整数n(2≤n≤106),表示 CSL 给 Compute 发壁纸的天数。

第二行有 n 个整数a1,a2,…,an(0≤ai≤100),分别表示第 i 天 CSL 给 Compute 发的小姐姐壁纸的吸引力为ai

输出描述

在一行输出一个正整数,表示 Compute 桌面壁纸至少出现过两张不同的小姐姐的方案数对 109+7取余后的结果。

样例

输入样例1

1
2
3
1 2 3

输出样例1

1
2

说明

对于第一个样例,Compute 有两种更换壁纸的方案:第 1 天和第 2 天换壁纸;第 1 天和第 3 天换壁纸。

输入样例2

1
2
6
1 1 4 5 1 4

输出样例2

1
17

输入样例3

1
2
7
1 9 1 9 8 1 0

输出样例3

1
18

输入样例4

1
2
9
8 2 0 2 3 3 0 1 6

输出样例4

1
64

输入样例5

1
2
30
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1

输出样例5

1
73741786

备注

Compute 可以在 CSL 发完壁纸的 n 天后继续使用他所正在使用最后的一张壁纸。

题解

线段树优化dp。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <cstdio>
#include <iostream>
#define Mod 1000000007
using namespace std;
const int N = 1000009;
int f[4*N], n, a[N];
void update(int l, int r, int rt, int p, int v)
{
if(r<p || l>p || l>r) return;
if(l==r)
{
f[rt] = v;
return;
}
int mid = (l + r) >> 1, lc = rt << 1, rc = rt << 1 | 1;
if(mid>=p) update(l, mid, lc, p, v);
else update(mid+1, r, rc, p, v);
f[rt] = (f[lc] + f[rc]) % Mod;
}
int query(int l, int r, int rt, int L, int R)
{
if(l>R || r<L || l>r || L>R) return 0;
if(L<=l && r<=R) return f[rt];
int mid = (l + r) >> 1, lc = rt << 1, rc = rt << 1 | 1;
int lv = query(l, mid, lc, L, R);
int rv = query(mid+1, r, rc, L, R);
f[rt] = (f[lc] + f[rc]) % Mod;
return (lv + rv) % Mod;
}
int main(int argc, char const *argv[])
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = n; i > 0; i--)
{
int l = i + a[i] + (a[i]==0);
if(l>n) continue;
int tmp = query(1, n, 1, l, n);
update(1, n, 1, i, n-l+1+tmp);
}
printf("%d\n", f[1]);
return 0;
}