题目链接:codeforces 776C
题目大意:一个数列,有n个元素,求有多少个连续区间,区间和为k^0,k^1,k^2…..
一开始的时候想到了sum数组存储前n项和,但如果遍历所有区间的话,复杂度为n^2
然后想到了对于每个sum[i]
,只要在前面找到一个sum[j], j<i
,满足sum[i] - sum[j] = k^x(x>=0)
;
所以我用map<int, vector<int> > mapp
存储每个sum值出现的位置,所以,对于每个sum[i]
, 遍历mapp[k^x - sum[i]]
,当mapp[k^x - sum[i] ][j] 0<=j<mapp[k^x - sum[i]].size()
,当mapp[k^x - sum[i] ][j] < i
时,(即前面存在一个sum[i']
,使得sum[i] - sum[i'] = k^x
),答案加一,但还是会超时。
看了别人的代码才想到,每次只需用的sum[i] 前面的sum,不需要开始就把所有的情况存入mapp,只需要每次把第i个存入就好了。这样就不需要遍历mapp[k^x - sum[i]]
在判断了,因为此时里面元素都是在i之前的。
特别要注意k==1 || k==-1的情况
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
const int MAXN = 100000 + 100;
typedef long long ll;
const ll INF = 1e15;
map<ll, ll> mapp;
ll a[MAXN], sum[MAXN];
ll n, k;
int main()
{
cin >> n >> k;
sum[0] = 0;
for(int i=1; i<=n; ++i)
{
scanf("%I64d", a+i);
sum[i] = sum[i-1] + a[i];
}
ll cnt = 0;
ll t = k;
mapp[0] = 1;
int nn = 60;
if(t==1) nn = 1;
else if(t==-1) nn = 2;
k = 1;
for(int i=1; i<=n; ++i)
{
for(int x=1; k>=-INF && k<=INF && x <=nn; ++x)
{
ll a = sum[i] - k;
if(mapp.find(a) != mapp.end()) cnt += mapp[a];
k*=t;
}
k=1;
mapp[sum[i]]++;
}
cout << cnt << endl;
return 0;
}