牛客题解 珂朵莉与宇宙

链接:https://ac.nowcoder.com/acm/problem/14600
来源:牛客网

题解

作者 岛田小雅

这道题很仁慈地直接告诉了我们子区间的个数,如果直接暴力遍历所有的子区间,复杂度是 \(O(\frac{n\times (n+1)}{2})\) 那肯定会 TLE。怎么办呢?如果有一种方法能在从左往右遍历数组 \(a\) 的时候就把所有信息都处理好,接下来只需要调用处理好的信息进行计算就好了。

首先,因为要求子区间的和,我们先弄个前缀和数组出来。这样我们就能轻易通过对前缀和的处理来找到需要的区间。对每个 \(qzh_i\),我们直接对所有的 \(qzh_j\)\(j<i\))进行计数,然后遍历所有平方数 \(q_k\)\(q_k\leqslant qzh_i\))。在每个 \(qzh_i\) 前出现的 \(qzh_j=qzh_i-q_k\) 的数量之和就是答案。

我们知道,前缀和最大应该是 \(n\times 10=1\times 10^6=N^2\)。也就是说,对每个数遍历比它小的所有平方数,它的复杂度是 \(O(n\times N)\)。总复杂度是 \(O(n+n\times N)\),问题不大。

注意,因为一共有 \(\frac{n\times (n+1)}{2}\) 个子区间,所以答案要开 \(\texttt{long long}\)(我没注意到所以 WA 了 2 发)

AC 代码

作者 岛田小雅
#include <bits/stdc++.h>
using namespace std;

const int N = 1e5+2;
const int MAXQZH = 1e6+2;
int n;
int a[N], qzh[N];
int cnt[MAXQZH];
long long ans;

int main()
{
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    cin >> n;
    cnt[0]++; // 因为qzh[i]如果自己就是个平方数的话,它可以选择从自己到前面的所有数作为一个区间,所以一开始就有一个0(相当于qzh[0]合法)
    for(int i = 1; i <= n; i++)
    {
        cin >> a[i];
        qzh[i] = qzh[i-1]+a[i];
        for(int j = 0; j*j <= qzh[i]; j++) ans += cnt[qzh[i]-j*j];
        cnt[qzh[i]]++;
    }
    cout << ans;
    return 0;
}
posted @ 2022-09-19 17:28  岛田小雅  阅读(45)  评论(0编辑  收藏  举报