F. Copy or Prefix Sum
题目链接:Copy or Prefix Sum
题目大意:给定一个
b
b
b数组,一个
a
a
a是合法的指对于每一个
i
i
i都有
b
i
=
a
i
b_i=a_i
bi=ai or
b
i
=
∑
j
=
1
i
a
j
b_i=\sum\limits_{j=1}^{i}a_j
bi=j=1∑iaj。问合法的
a
a
a有多少个。
数据范围:
1
≤
t
≤
1
e
4
,
1
≤
∑
n
≤
2
e
5
,
−
1
e
9
≤
b
i
≤
1
e
9
1\le t\le 1e4,1\le \sum n\le 2e5,-1e9\le b_i\le 1e9
1≤t≤1e4,1≤∑n≤2e5,−1e9≤bi≤1e9
题解:考虑
d
p
dp
dp,
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示
[
1
−
i
]
[1-i]
[1−i]中有多少种情况
(
∑
j
=
1
i
a
i
)
=
=
j
(\sum\limits_{j=1}^{i}a_i)==j
(j=1∑iai)==j。答案显然是
∑
j
=
−
i
n
f
i
n
f
d
p
[
n
]
[
j
]
\sum\limits_{j=-inf}^{inf}dp[n][j]
j=−inf∑infdp[n][j]。现在来考虑转移,对于
a
[
i
]
a[i]
a[i]来说可以等于
b
[
i
]
o
r
b
[
i
]
−
s
u
m
[
i
−
1
]
b[i] or b[i]-sum[i-1]
b[i]orb[i]−sum[i−1]
a
[
i
]
a[i]
a[i]等于
b
[
i
]
b[i]
b[i]的情况,对于
j
∈
[
−
i
n
f
,
i
n
f
]
j\in[-inf,inf]
j∈[−inf,inf]都有
d
p
[
i
]
[
j
]
=
d
p
[
i
−
1
]
[
j
−
b
[
i
]
]
dp[i][j]=dp[i-1][j-b[i]]
dp[i][j]=dp[i−1][j−b[i]]
a
[
i
]
a[i]
a[i]等于
b
[
i
]
−
s
u
m
[
i
−
1
]
b[i]-sum[i-1]
b[i]−sum[i−1]的情况,可以发现
(
∑
j
=
1
i
a
[
i
]
)
=
b
[
i
]
(\sum\limits_{j=1}^{i}a[i])=b[i]
(j=1∑ia[i])=b[i],所以
d
p
[
i
]
[
b
[
i
]
]
=
∑
j
=
−
i
n
f
i
n
f
d
p
[
i
−
1
]
[
j
]
dp[i][b[i]]=\sum\limits_{j=-inf}^{inf}dp[i-1][j]
dp[i][b[i]]=j=−inf∑infdp[i−1][j]。我们可以使用
m
a
p
map
map来进行转移,每次
i
−
>
i
+
1
i->i+1
i−>i+1将
m
a
p
map
map内的元素都修改一次。时间复杂度
O
(
n
2
l
o
g
n
)
O(n^2logn)
O(n2logn)。不过对于这种全局修改的转移,可以使用一种"水位线技术"。参见博客。可以设置一个全局变量,让转移变成
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。其中
l
o
g
log
log是
m
a
p
map
map自带的。
AC代码:
#include<bits/stdc++.h>
#define ld long double
#define ll long long
using namespace std;
template<class T>
void read(T& x)
{
T res = 0, f = 1; char c = getchar();
while (!isdigit(c)) {
if (c == '-')f = -1; c = getchar();
}
while (isdigit(c)) {
res = (res << 3) + (res << 1) + c - '0'; c = getchar();
}
x = res * f;
}
#define int long long
const ll N = 200000 + 10;
const int mod = 1e9 + 7;
int t, n, b[N];
map<int, int>mp;
signed main()
{
//ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("test.in", "r", stdin);
#endif // ONLINE_JUDGE
read(t);
while (t--)
{
int wel = 0, tol = 0;
read(n);
mp.clear();
mp[0] = 1, tol = 1;
for (int i = 1; i <= n; i++)read(b[i]);
for (int i = 1; i <= n; i++)
{
wel -= b[i];
int change = tol - mp[b[i] + wel];
mp[b[i] + wel] = tol;
tol = (tol + change)%mod;
}
printf("%lld\n", (tol % mod + mod)%mod);
}
return 0;
}