F. Copy or Prefix Sum(优化dp转移)

文章目录

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=1iaj。问合法的 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 1t1e4,1n2e5,1e9bi1e9
题解:考虑 d p dp dp d p [ i ] [ j ] dp[i][j] dp[i][j]表示 [ 1 − i ] [1-i] [1i]中有多少种情况 ( ∑ j = 1 i a i ) = = j (\sum\limits_{j=1}^{i}a_i)==j (j=1iai)==j。答案显然是 ∑ j = − i n f i n f d p [ n ] [ j ] \sum\limits_{j=-inf}^{inf}dp[n][j] j=infinfdp[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[i1]
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[i1][jb[i]] a [ i ] a[i] a[i]等于 b [ i ] − s u m [ i − 1 ] b[i]-sum[i-1] b[i]sum[i1]的情况,可以发现 ( ∑ j = 1 i a [ i ] ) = b [ i ] (\sum\limits_{j=1}^{i}a[i])=b[i] (j=1ia[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=infinfdp[i1][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;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值