SP32192 SUMMATION - SUMMATION

题目大意

给定有 $n$ 个数的数列 $s$,求这个数列的所有子序列之和的总和。答案对 $100000007$ 取模。

题意分析

观察样例表格。

易得,包括空序列在内,总的子序列数为 $8$,即 $2^3$。

也就是,对于有 $n$ 个数的数列,总的子序列数为 $2^n$。

对于一个数列中的元素 $s_i$,在所有数列中都有 $\frac12$ 存在 $s_i$,另一半不存在。也就是说,仅计算这个元素在所有序列中的和,为

$$s_i\times \frac12 \times 2^n = s_i \times 2^{n-1}$$

题目中所求的就是所有元素套上述式子的总和,即

$$ans = \sum_{i=1}^{n}s_i \times 2^{n-1} = 2^{n-1}\sum_{i=1}^{n}s_i$$

那么只要在输入的时候累加求和,再用快速幂算出 $2^{n - 1}$ 并相乘取模即可。

主要芝士

快速幂

我们知道,乘方运算有结合律,即 $x^a\times x^b = x^{ab}$。

所以我们就可以对 $f(n,k,p) = n^k \ \bmod \ p$ 进行分解:

$$ f(n,k,p) = \begin{cases} f(n,\frac12k,p)^2\ \bmod\ p & (k\ \bmod\ 2 = 0) \\ f(n,\frac12(k-1),p)^2\ \times n \ \bmod\ p &(k\ \bmod\ 2 = 1) \end{cases}$$

代码:

int power(int base, int freq, int mod) {
    int ans = 1, tmp = base;
    while (freq) {
        if (freq & 1) ans = ans * tmp % mod;
        freq >>= 1;
        tmp = tmp * tmp % mod;
    }
    return ans;
}

时间复杂度仅 $O(\log n)$。比起循环乘的 $O(n)$ 快了不少。

题目坑点

模数居然不是 $10^9+7$,而是 $10^8+7$,差评。

另:开 long long

完整代码

#include <bits/stdc++.h>
#define int long long

using namespace std;

int t, n, ai, sum, res;
const int mod = 1e8 + 7;

int power(int base, int freq, int mod) {
    int ans = 1, tmp = base;
    while (freq) {
        if (freq & 1) ans = ans * tmp % mod;
        freq >>= 1;
        tmp = tmp * tmp % mod;
    }
    return ans;
}

signed main() {
    cin >> t;
    for (int cs = 1; cs <= t; cs++) {
        sum = 0;
        cin >> n;
        for (int i = 1; i <= n; i++) {
            cin >> ai;
            sum = (sum + ai) % mod;
        }
        res = sum * power(2, n - 1, mod) % mod;
        cout << "Case " << cs << ": " << res << endl;
    }
    return 0;
}

(不要脸地求个赞)

posted @   TernaKagiri  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
点击右上角即可分享
微信分享提示