Codeforces Round #400 Molly's Chemicals 前綴和

題目:

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 2
2 2 2 2
output
8
input
4 -3
3 -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);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章