>Link
luogu U137902
>Description
这里用mina表示数组中的最小值,用maxa表示数组中的最大值。
对于前30%的测试点,n<=10,maxa<=10。
对于前60%的测试点,n<=100。
对于前80%的测试点,mina>=2。
对于100%的测试点,n<=2e5,k<=1e5,maxa<=1e8,mina>=1。
>解题思路
麻了,比赛的时候一直在推式子,方向直接错了QAQ
暴力,先固定一个左端点,然后再把右端点往后移,时间复杂度为 O ( n 2 ) O(n^2) O(n2)
80分:
然后我们发现题目给的式子可以转换为
∏
i
=
l
r
a
i
=
k
∑
i
=
l
r
a
i
\prod_{i=l}^ra_i=k\sum _{i=l}^ra_i
∏i=lrai=k∑i=lrai
a
i
a_i
ai和
k
k
k的最大值题目已经给出,所以我们可以(计算器)求出等式右边的最大值为
2
∗
1
0
8
2*10^8
2∗108
暴力的时候,如果乘积超过了longlong的范围,就可以直接break了,因为右边不可能超过longlong,而
a
i
a_i
ai最小为2,每次多加一个数乘积就会变大
时间复杂度大概为
O
(
61
∗
n
)
O(61*n)
O(61∗n)
100分:
a
i
a_i
ai的最小值变成了1
那我们就把全部为1的区间整个一起处理,因为乘积是不变的,如果有满足条件的就ans++
这样就跟上面的一样了
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
#define LL long long
using namespace std;
int n, k, nxt[N], len;
LL a[N], ans, p1, p2;
int main()
{
scanf ("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf ("%lld", &a[i]);
for (int i = n; i >= 1; i--)
{
nxt[i] = i;
if (a[i + 1] == 1 && a[i] == 1) nxt[i] = nxt[i + 1];
}
for (int i = 1; i <= n; i++)
{
p1 = 1, p2 = 0;
for (int j = i; j <= n; j++)
{
if (a[j] == 1)
{
len = nxt[j] - j + 1;
if (p1 > p2 && (p1 - p2) % k == 0 && (p1 - p2) / k <= len)
ans++;
p2 += k * len;
j = nxt[j];
}
else
{
p1 *= a[j], p2 += a[j] * k;
if (p1 > 2000000000000000000) break;
if (p1 == p2) ans++;
}
}
}
printf ("%lld", ans);
return 0;
}