题目翻译

给定长度为 $n$ 的序列 $a$,求有多少组 $(l,r)$ 满足 $\sum\limits_{i=l}^ra_i=k^i$。

题目思路

首先考虑,枚举 $l$ 和 $r$,判断 $\sum\limits_{i=l}^r$ 是否为 $k$ 的倍数。但是显然这种做法复杂度为 $n^2$ 无法通过。

设 $s$ 为 $a$ 的前缀和数组,我们注意到,我们查找 $s_r-s_{l-1}=k^i$,其实等价于找 $s$ 中是否有 $s_r-k^i$ 这个元素,那么我们只需枚举一个端点以及一个 $k$ 的次幂。

显然在这个题中,除去 $k=\pm1$,上述的 $i$ 最多只需枚举至 $\log_2 (10^9\times 10^5)\approx 60$ 次。

因此,总的时间复杂度为 $\mathcal O(n\times 60)$。对于 C++ 选手,如果你用 map 来判断 $s_r-k^i$ 是否存在还需乘上一个 $\log_2 n$。

完整代码

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
int n;
ll st[100];
int top;
ll pw=1;
ll k,ans;
ll a[100020];
ll s[100020];
map<ll,int>mp;
int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        s[i]=a[i]+s[i-1];
    }
    for(int i=0;i<=60;i++)
    {
        if(abs(pw)>1e14)break;
        st[++top]=pw;
        pw*=k;
    }
    mp[0]=1;
    for(int i=1;i<=n;i++)
    {
        if(k==1)ans+=mp[s[i]-1];
        else if(k==-1)ans+=mp[s[i]-1]+mp[s[i]+1];
        else 
        {
            for(int _=1;_<=top;_++)
            {
                ans+=mp[s[i]-st[_]];
            }
        }
        mp[s[i]]++;
    }
    cout<<ans<<endl;
    return 0;
}
最后修改:2023 年 04 月 22 日
v我50吃疯狂星期四