**
A.珂朵莉与宇宙
**
题目描述
星神是来自宇宙的
所以珂朵莉也是吧
所以我就出了个题
给你一个长为n的序列a,有n*(n+1)/2个子区间,问这些子区间里面和为完全平方数的子区间个数
输入描述:
第一行一个数n
第二行n个数表示序列a
输出描述:
输出一个数表示答案
示例1
输入
6
0 1 0 9 1 0
输出
11
备注:
1 <= n <= 100000
0 <= ai <= 10
解题思路:前缀和求解问题。看数据范围就知道一定有什么神秘操作。
a[]数组存放前缀和。 b[]数组作为标记(哪些前缀和出现过),O(n)跑一边,在每个i的位置枚举小于等于a[i]的平方数。
例如样例中, 我们举个栗子,现在到9,也就说 a[i] = 10, b[0] = 2, b[1] = 2。这是我们的已知条件,那么现在就要枚举从j = 0 开始, 第一个是 j = 0, a[i] - j*j = 10,
b[10] = 0; 第二个是 j = 1, a[i] - j* j = 9,b[9] = 0; 第三个是 j = 2, a[i] - j* j = 6,b[6] = 0; 第四个是 j = 3, a[i] - j*j = 1,b[1] = 2; -> res += 2.(为什么这里加2,第一种是 9,第二种是 0 和 9),当j = 4 的时候就退出循环。
理解到这里,这道题基本已经完成啦。
还需要注意到几个点: 对于复杂度的计算。 1 <= n <= 100000,0 <= ai <= 10, 最大的前缀和是 1e6, 枚举的最大值就是 1000,所以复杂度是 O(1e8),时间给了2s,足够。
第二点就是注意b[i]的数组大小和,res要用long long。
#include<bits/stdc++.h>
using namespace std;
int a[110000];
int b[1100000];
int main ()
{
//yyy_3y
int t; scanf("%d",&t);
for (int i = 1; i <= t; i++){
scanf("%d",&a[i]);
a[i] += a[i-1];
}
long long res = 0;
b[0] = 1;
for (int i = 1; i <= t; i++){
for (int j = 0; j*j <= a[i]; j++){
res += b[a[i] - j*j];
}
b[a[i]]++;
}
printf("%lld\n",res);
return 0;
}