这是问题所在,我试图在SPOJ中解决。我的时间限制超出了问题。我无法找到优化算法的方法。你能给我一些提示吗?
问题在于:
伦纳德必须找到连续数字序列的数量 他们的总和是零。
例如,如果序列是-5,2,-2,5,-5,9
有3个这样的序列
2,-2
5,-5
2,-2,5,-5
因为这是伦纳德重写室友的绝佳机会 协议和摆脱谢尔顿的荒谬条款,他无法承受 失去。所以他转向你寻求帮助。别让他失望。
输入
第一行包含T个测试用例数
第二行包含n - 特定测试中的元素数 情况下。
下一行包含n个元素,ai(1< = i< = n)用空格分隔。
输出
此类序列的数量,其总和为零。
约束
1·; = T< = 5
1·; = N&LT = 10 ^ 6
-10< = ai< = 10
以下是我的代码:
#include<stdio.h>
main()
{
int t, j, k, l, sum;
long long int num, out = 0;
long long int ai[1000001];
scanf("%d",&t);
while(t--)
{
for(j=0;j<=num;j++)
{
scanf("%lld",&ai[j]);
}
for(l=0;l<=num;l++)
{
for(k=l; k<=num; k++)
{
if(sum == 0)
{
num++;
}
else
{
sum = sum + ai[k];
}
}
printf("%d", &num);
}
}
return 0;
}
答案 0 :(得分:0)
设S [i]是从索引0到索引i(前缀和)的元素之和。设置S [-1] = 0。
你可以观察到,如果从索引i到索引j(j> i)的序列总和为0,则S [j] - S [i-1] = 0,或者S [j] = S [i- 1]。
为了解决这个问题,只需将S [i](i = -1 .. n-1)的值映射到总和的频率。如果特定和总和重复k次,则可以选择2种方法来配对索引以创建不同的序列。您可以通过总结所有方法来获得序列总数,方法是通过所有键并检查最后的频率。
对于插入和更新操作,映射的实现最多应为 O(log n)。这将允许您解决 O(n log n)的总体复杂性问题:前缀sum O(n),插入/更新地图 O (n log n),浏览整个地图以总结结果 O(n)。
伪代码:
a[n] // Array of elements
m = new Map[Int->Int] // Frequency mapping
s = 0 // Prefix sum
m[s] += 1
for (i = 0; i < n; i++) {
s += a[i] // Prefix sum of array of elements a
m[s] += 1 // Increment frequency of the prefix sum by 1
}
out = 0
// Go through all key values in the map
m.traverse(function (key, value) {
// Add the number of pairs of indices that has the same prefix sum
out += value * (value - 1) / 2
})
return out
答案 1 :(得分:0)
这是我的解决方案,它类似于nhahtdh,但时间复杂度为O(n)
伪代码:
int pos[10000001];
int neg[10000001];
int sum = 0;
int result = 0;
for(int i = 0; i < arr.length; i++){
sum += arr[i];
if(sum > 0){
result += pos[sum];
pos[sum]++;
}else{
result += neg[-sum];
neg[-sum]++;
}
}
return result;