前缀和变形:和与乘积

定义: 乘积等于和的区间为合法区间

根据数据范围分析“积”与“和”的情况

a i a_i ai的范围是1~200000, n n n的范围是1~200000,则区间和的最大值等于最大区间长度 × \times × 元素的可取最大值 = 200000 × 200000 < 2 36 = 200000\times 200000<2^{36} =200000×200000<236, 将一个区间内大于 1 1 1 的数的个数记为 t o t tot tot,那么对于任意一个合法区间都满足 t o t < 36 tot < 36 tot<36
一个区间的的乘积显然 ≥ 2 t o t \geq 2^{tot} 2tot;当一个区间的 t o t ≥ 36 tot\geq 36 tot36 或者说乘积大于等于 200000 × 200000 200000\times 200000 200000×200000 时该区间不是合法区间
定义 s u m [ i ] sum[i] sum[i] 表示 a 1 + a 2 + ⋯ + a i a_1+a_2+\cdots+a_i a1+a2++ai,区间 [ L , R ] [L,R] [L,R] 的和用 s u m [ R ] − s u m [ L − 1 ] sum[R]-sum[L-1] sum[R]sum[L1] 得到了。

步骤

1、将大于 1 1 1 的元素的下标按顺序记录在 v e c t o r vector vector 里,然后枚举区间左端点。确定了左端点后再从 v e c t o r vector vector 里枚举合法区间的右端点,这样枚举的总复杂度不超过 O ( n × 36 ) O(n\times 36) O(n×36)
2、设枚举的左端点为 L L L,右端点为 R R R,那么区间的和为 s u m [ R ] − s u m [ L − 1 ] sum[R]-sum[L-1] sum[R]sum[L1],区间的乘积我们也可以在枚举右端点过程中求出(记乘积值为 n o w now now)。
3、要使区间合法,需满足 s u m [ R ] − s u m [ L − 1 ] = n o w sum[R] - sum[L-1] = now sum[R]sum[L1]=now。而如果 s u m [ R ] − s u m [ L − 1 ] < n o w sum[R] - sum[L-1] < now sum[R]sum[L1]<now,则我们需要在不影响区间乘积值的情况下,右移区间(即添加 n o w − ( s u m [ R ] − s u m [ L − 1 ] ) now - (sum[R] - sum[L-1]) now(sum[R]sum[L1]) 个值为 1 1 1 的元素)
4、记录每个大于 1 1 1 的元素后面有多少个值为 1 1 1 的连续的元素。 记每个大于 1 1 1 的元素后有 s u f suf suf 个连续的 1 1 1,那么只要满足 n o w ≤ s u m [ R ] − s u m [ L − 1 ] + s u f now \leq sum[R]-sum[L-1] + suf nowsum[R]sum[L1]+suf 即可通过右移区间使得区间合法。

如果 s u m [ R ] − s u m [ L − 1 ] > n o w sum[R]-sum[L-1] > now sum[R]sum[L1]>now,显然在不改变 n o w now now 的情况下我们是无法使区间合法的。

INF = 40000000000
n = int(input())
array = list(map(int,input().split()))
suf = [0 for _ in range(n+2)]
vec = []
sumlist = [0 for _ in range(n+2)]
tot = 0
index = 0
while index < n:
    if array[index] > 1:
        vec.append(index)
        tot += 1
    sumlist[index] = sumlist[index-1] + array[index]
    index += 1
res = 0
cnt = 0
for i in range(n-1,-1,-1):
    if array[i] > 1:
        suf[i] = cnt
        cnt = 0
    else:
        cnt += 1
index = 0
while index < n:
    res +=1
    now = array[index]
    L = 0
    R = tot - 1
    pos = n
    while L <= R:
        mid = L + R >> 1
        if vec[mid] > index:
            R = mid - 1
            pos = mid
        else:
          L = mid + 1
    j =pos
    while j < tot:
        now *=array[vec[j]]
        if now > INF:
            break

        sumof = sumlist[vec[j]]-sumlist[index-1]
        if sumof <= now and \
            now <= sumof + suf[vec[j]]:
            res += 1
        j+=1
    index += 1
print(res)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雨拾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值