Codeforces Round #400 Molly's Chemicals 前缀和

来源:互联网 发布:河北农业科技网络书屋 编辑:程序博客网 时间:2024/05/17 06:26

题目:

C. Molly's Chemicals
time limit per test
2.5 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output

Molly Hooper has n different kinds of chemicals arranged in a line. Each of the chemicals has an affection value, The i-th of them has affection value ai.

Molly wants Sherlock to fall in love with her. She intends to do this by mixing a contiguous segment of chemicals together to make a love potion with total affection value as a non-negative integer power ofk. Total affection value of a continuous segment of chemicals is the sum of affection values of each chemical in that segment.

Help her to do so in finding the total number of such segments.

Input

The first line of input contains two integers, n and k, the number of chemicals and the number, such that the total affection value is a non-negative power of this number k. (1 ≤ n ≤ 1051 ≤ |k| ≤ 10).

Next line contains n integers a1, a2, ..., an ( - 109 ≤ ai ≤ 109) — affection values of chemicals.

Output

Output a single integer — the number of valid segments.

Examples
input
4 22 2 2 2
output
8
input
4 -33 -6 -3 12
output
3
Note

Do keep in mind that k0 = 1.

In the first sample, Molly can get following different affection values:

  • 2: segments [1, 1][2, 2][3, 3][4, 4];

  • 4: segments [1, 2][2, 3][3, 4];

  • 6: segments [1, 3][2, 4];

  • 8: segments [1, 4].

Out of these, 24 and 8 are powers of k = 2. Therefore, the answer is 8.

In the second sample, Molly can choose segments [1, 2][3, 3][3, 4].


这种求多少个区间满足条件的题,一直是我的一大软肋,0rzzz。

设sum[i]=sigma(a[0...i]) (其实i表示的就是前前缀和的右端点) 这个题意思就是,求sum[j]-sum[i]=k^p(p=0,1,2,3...)(j>=i)。

我自己能想到的解法也就只有暴力枚举了i,j了,O(n^2)还是死了这条心吧。其实还是枚举,不过我们得换一个姿势。

注意到k^p不超过1e14,那么最差情况下(1,-1分别讨论),我们需要枚举幂p [log2 (1e14)]+1<50故,我们可以考虑枚举p和右前缀和的右端点j也就是说 sum[j]-k^p=sum[i],sum[i]有几个答案ans就加上几,考虑用map存储个数。

code:

#include<cmath>
#include<map>
#include<cstdio>
using namespace std;
typedef long long LL;
const int MAXN=1e5+5;
const LL INF=1e15+5;
LL sum[MAXN];
map<LL,int>cnt;
int main(){
    LL n,k;scanf("%I64d%I64d",&n,&k);
    sum[0]=0;
    for(int i=1;i<=n;++i){
        LL a;scanf("%I64d",&a);
        sum[i]=sum[i-1]+a;
    }
    LL res=0;
    if(k==1){
        for(int i=0;i<=n;++i){
            cnt[sum[i]]++;//1的不论多少次方都是1
            res+=cnt[sum[i]-1];
        }
    }
    else if(k==-1){
        for(int i=0;i<=n;++i){
            cnt[sum[i]]++;//-1的奇数次方是-1,偶数次方是1
            res+=cnt[sum[i]-1]+cnt[sum[i]+1];
        }
    }
    else {
        for(int i=0;i<=n;++i){//枚举前缀和右端点
            cnt[sum[i]]++;
            LL val=1;//val 代表k的p次方的值
            for(;;){//枚举k^p
                res+=cnt[sum[i]-val];
                val*=k;
                if(val>INF||val<-INF)break;
            }
        }
    }
    printf("%I64d\n",res);
}

其实在写这个题期间我还犯了一个巨大的错误:

    sum[0]=0; cnt[0]++;
    for(int i=1;i<=n;++i){
        LL a;scanf("%I64d",&a);
        sum[i]=sum[i-1]+a;
        cnt[sum[i]]++;

    }

然后像这样枚举。

    int res=0;
    for(int i=0;i<=n;++i)
    for(int p=0;;++p){
        LL val=pow(k,p);
        if(val>INF||val<-INF)break;
        res+=cnt[sum[i]-val];//tag
        if(cnt[sum[i]-val]>=1){
            //printf("sum[i]=%I64d,val=%I64d\n",sum[i],val);
        }

错误的原因在于没理解到时枚举右端点,在tag处得到的值可能跑到右端点右边去了,这显然会重复。下次注意吧。

题外话:每次看前面的哪些神牛的代码都太感叹了。能够在这么短的时间内写出这么对的优雅的代码。贴一个ainta的

#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
map<long long, int>Map;
int n, K;
long long s, res, t;
int main(){
    int a, i;
    scanf("%d%d",&n,&K);
    Map[0] = 1;
    for(i=1;i<=n;i++){
        scanf("%d",&a);
        s += a;
        if(K==1){
            res += Map[s-1];
        }
        else if(K==-1){
            res += Map[s-1] + Map[s+1];
        }
        else{
            t = 1;
            while(1){
                res += Map[s-t];
                t*=K;
                if(t > 1e15 || -t > 1e15)break;
            }
        }
        Map[s]++;
    }
    printf("%lld\n",res);
}

0 0
原创粉丝点击