Codeforces Round #400 (Div. 1 + Div. 2, combined) C. Molly’s Chemicals 区间和、构造、前缀的后缀

ProLightsfx 2017-7-31 126 7/31
C. Molly's Chemicals 区间和、构造、前缀的后缀

My Solution

题意:给出n个数字,要求选出一段连续的数字,使它的和为k的非负整数次方,为这样的区间有多少个。

 

区间和、构造、前缀的后缀

这是一个很有趣的构造题,一个连续区间[a, b],转化为 [1, b] - [1,a-1],如果差值,满足要求则这样的区间存在,

然后换过来,对于每个k^j,对于 [1,b] - k^j == [1,ax-1],有多少个前缀和sum{[1,ax-1]}就有多少个多少个区间[ax, b] == k^j次。

这里可以借助map来记录 前缀和sum{[1,ax-1]} 出现的次数。

此外要处理2种特殊的情况,一种是k == -1,这时pow_k[j] 只对 -1和1进行讨论, 还有一种是 k == 1,这时pow_k[j]只对 1 进行讨论。

从而巧妙的把这个问题从O(n^2)优化到了O(n)

复杂度 O(n)

 

#include 
#include 
#include 



#include 
using namespace std;
typedef long long LL;
typedef pair<int, int> ii;
const int MAXN = 1e5 + 8;
const LL INF = 1e14 + 8;

map<LL, LL> mp;
LL a[MAXN], pow_k[66];

int main()
{
    #ifdef LOCAL
    freopen("c.txt", "r", stdin);
    //freopen("c.out", "w", stdout);
    int T = 4;
    while(T--){
    #endif // LOCAL
    ios::sync_with_stdio(false); cin.tie(0);

    LL n, k, cnt, i, j, ans = 0, sum = 0;
    cin >> n >> k;
    for(i = 1; i <= n; i++) cin >> a[i];
    if(k == 1){cnt = 1; pow_k[0] = 1;}
    else if(k == -1){cnt = 2; pow_k[0] = 1; pow_k[1] = -1;}
    else{
        pow_k[0] = 1;
        for(i = 1; i < 66; i++){ if(abs(pow_k[i-1]*k) >= INF){cnt = i; break;}
            pow_k[i] = pow_k[i-1] * k;
        }
    }
    mp[sum]++;
    for(i = 1; i <= n; i++){
        sum += a[i];
        for(j = 0; j < cnt; j++){
            ans += mp[sum - pow_k[j]];
        }
        mp[sum]++;
    }
    cout << ans << endl;

    #ifdef LOCAL
    mp.clear();
    cout << endl;
    }
    #endif // LOCAL
    return 0;
}

 

 

非特殊说明,本博所有文章均为博主原创,未经许可不得转载。

https://www.prolightsfxjh.com/

Thank you!

                                                                                                                                             ------from ProLightsfx

- THE END -

ProLightsfx

11月17日01:30

最后修改:2024年11月17日
0

非特殊说明,本博所有文章均为博主原创,未经许可不得转载。

共有 0 条评论