题目链接: D. Nastya and a Game
题目大意
一个数组a, 有n个元素, 1≤n≤2⋅105 1 ≤ n ≤ 2 ⋅ 10 5 , 1≤a[i]≤1018 1 ≤ a [ i ] ≤ 10 18 , 求有多少区间 [l,r] [ l , r ] 满足 ps=k,p=∏ri=la[i],s=∑ri=la[i],k为给定常数,1≤k≤105 p s = k , p = ∏ i = l r a [ i ] , s = ∑ i = l r a [ i ] , k 为 给 定 常 数 , 1 ≤ k ≤ 10 5
思路
ps=k→p=s⋅k
p
s
=
k
→
p
=
s
⋅
k
, 因为
p=s⋅k≤2⋅105⋅1018⋅105=2⋅1018
p
=
s
⋅
k
≤
2
⋅
10
5
⋅
10
18
⋅
10
5
=
2
⋅
10
18
,所以区间中大于1的元素个数应该要小于60(
261≈2.3⋅1018
2
61
≈
2.3
⋅
10
18
), 对于所有l,循环r,当区间p大于
218
2
18
时,退出循环,l++
为了减小复杂度,记录每个大于等于2的元素位置,当p>=s*k
, 要往区间里面加值为1的元素,判断当前位置到下一个大于等于2的元素位置是否有足够的1使得p==s*k
,然后r调到下一大于等于2的元素位置继续运行
代码
GNU C++17 Accepted 499 ms 1580 KB
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 100;
const ll MAX = 2E18 + 100;
int n, k, a[maxn];
int pos[maxn], cnt;
int main()
{
cin >> n >> k;
for (int i = 0; i < n; ++i)
{
cin >> a[i];
if (a[i] > 1) pos[cnt++] = i;
}
pos[cnt++] = n;
ll s, p, ans = 0;
for (int l = 0; l < n; ++l)
{
s = p = a[l];
for (int r = l; r < n; )
{
int nxt = pos[upper_bound(pos, pos + cnt, r) - pos];
if (p >= s * k && p % k == 0)
{
ll need1 = p / k - s;
if (nxt - r - 1 >= need1) ++ans;
}
if(nxt == n) break;
s += a[nxt] + nxt - r - 1;
if (p >= MAX / a[nxt]) break;
p *= a[nxt];
r = nxt;
}
}
cout << ans << endl;
return 0;
}