如何存储数组的每个相邻子数组的和

How to store the sum of every contigous subarray of an array?

本文关键字:数组 何存储 存储      更新时间:2023-10-16

我有一个n个元素的数组(1 <= n <= 200000)。我要找出这个数组中所有相邻子数组的和。我有一个O(n^2)的算法可以找到所有的和,但我的问题是我不能把它存储在任何数据结构中因为有n(n+1)/2个元素。因此将有10^10个元素,这将需要很大的空间。这是我得到的输出。

terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc Aborted (core dumped)

我猜是因为我的代码使用了太多的内存。以下是我的代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long int lli;
#define vi vector<int>
#define vli vector<lli>
#define dqi deque<int>
#define MOD 10e9+7
#define mis map<int,string>
#define msi map<string,int>
#define set0(a) memset(a,0,sizeof(a))
#define sc scanf
#define pr printf
#define rint(a) sc("%d",&a)
#define rchar(a) sc("%d",&a)
#define pb push_back
#define pf push_front
#define rstring(s) sc("%s",&s)
#define rp(a,b,c) for(int (a)=(b);(a)<(c);(a)++)
#define rpn(a)  while(a--)
int a[200010],t=0,n=0,q=0,cnt=0;
vector<long long int> b;
long long int l=0,r=0;
int main()
{
  freopen("in.txt","r",stdin);
  freopen("out.txt","w",stdout);
  memset(a,0,sizeof(a));
  scanf("%d",&t);
  while(t--){
    scanf("%d %d",&n,&q);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    long long int sum=0;
    for(int i=n-1,j=1;i>=0;i--,j++){
        b.push_back(a[i]);sum=a[i];
        for(int j=i+1;j<=n-1;j++)
                b.push_back(sum+=a[j]);
    }
    //following part find the sum of elements of subarrays in a given range after sorting them
    printf("Case #%d: n",++cnt);
    while(q--){
        scanf("%lld %lld",&l,&r);
        long long int sum=0;
        for(long long int i=l-1;i<r;i++)
            sum+=b[i];
        printf("%lldn",sum);
    }
    b.clear();
}
return 0;
}

还有别的方法吗?请指导。

您可以使用通常用于这类问题的段树。浏览下面的链接

https://www.hackerearth.com/practice/notes/segment-tree-and-lazy-propagation/

可以将元素的和存储在根目录中,而不是给定的两个元素的差值(在链接中给出)。

您正在获得'std::bad_alloc',因为您试图分配如此多的静态内存。静态内存的分配是有限制的,这取决于环境:您在哪个操作系统中运行它?那是16位、32位、64位的内存架构吗?更多信息。

<

交替方式/h4>

另一种方法需要O(n)个时间和O(n)个辅助空间。你不需要计算每个连续子数组的和。相反,计算并存储到初始数组的第i个元素的和到一个新数组中。

如果初始数组(A)为[5,3,9,15,21],则新数组(B)将为[5,8,17,32,53]。

无论何时你需要连续子数组[l, r](包括两个)的和,其中l是左索引(或开始索引),r是右索引(或结束索引),你可以在O(1)时间内得到它,这个和将等于B[r] - B[l] + A[l]

下面是相同的实现。

# include <bits/stdc++.h>
using namespace std;
int main() {
    long long n; // number of elements in the array
    cin >> n;
    vector<long long> A(n), B(n); // A is the initial array (array with no modifications)
                                  // B is the calculated array (ith element of B contains sum up to the ith element of A)
    for (long long i = 0; i < n; i++) {
        cin >> A[i];
        if (i == 0) {
            B[i] = A[i];
        }
        else {
            B[i] = A[i] + B[i - 1];
        }
    }
    int q; // number of queries
    cin >> q;
    while (q--) {
        int l, r; // l is the left index (or starting index, zero based)
                  // r is the right index (or ending index, zero based)
        cin >> l >> r;
        cout << (B[r] - B[l] + A[l]) << endl; // sum of contiguous subarray [l, r] (both inclusive)
    }
    return 0;
}