Educational Codeforces Round 148 (Rated for Div. 2) E. Combinatorics Problem(递推/组合数)

文章讲述了如何将给定数组的k+1阶前缀和问题转化为组合数的计算,并利用递推关系简化求解过程,最终给出时间复杂度和AC代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题链接:E. Combinatorics Problem


题目大意:


给定一个长度为 n n n 的数组 a a a (按照原题的公式获得) 和一个正整数 k k k,你要计算一个长度为 n n n 的新数组 b b b ,其中:

  • b 1 = ( C k 1 ⋅ a 1 ) m o d    998244353 ; b_1=(C_{k}^{1}\cdot a_1)\mod 998244353; b1=(Ck1a1)mod998244353;
  • b 2 = ( C k 2 ⋅ a 1 + C k 1 ⋅ a 2 ) m o d    998244353 ; b_2=(C_{k}^{2}\cdot a_1+C_{k}^{1}\cdot a_2)\mod 998244353; b2=(Ck2a1+Ck1a2)mod998244353;
  • b 3 = ( C k 3 ⋅ a 1 + C k 2 ⋅ a 2 + C k 1 ⋅ a 3 ) m o d    998244353 b_3=(C_{k}^{3}\cdot a_1+C_{k}^{2}\cdot a_2+C_{k}^{1}\cdot a_3)\mod 998244353 b3=(Ck3a1+Ck2a2+Ck1a3)mod998244353,以此类推。

具体而言, b i = ( ∑ j = 1 i C k i − j + 1 ⋅ a j ) m o d    998244353 b_i=(\sum_{j=1}^{i}C_{k}^{i-j+1} \cdot a_j) \mod 998244353 bi=(j=1iCkij+1aj)mod998244353

现在你要输出这个 b b b 数组的异或和。

解题思路:


看起来十分困难,我们看看能不能转化成递推的形式获得。

假设 k = 2 k=2 k=2 ,那么我们的 b b b 数组会是这样的:
b 1 = a 1 b 2 = 3 ⋅ a 1 + a 2 b 3 = 6 ⋅ a 2 + 3 ⋅ a 2 + a 3 b 4 = 10 ⋅ a 2 + 6 ⋅ a 2 + 3 ⋅ a 3 + a 4 \begin{array}{l} b_1=a_1\\ b_2=3\cdot a_1+a_2\\ b_3=6\cdot a_2+3\cdot a_2+a_3\\ b_4=10\cdot a_2+6\cdot a_2+3\cdot a_3+a_4\\ \end{array} b1=a1b2=3a1+a2b3=6a2+3a2+a3b4=10a2+6a2+3a3+a4

假设 b 0 = 0 b_0=0 b0=0 我们对相邻两项作差看看会得到什么。

Δ 1 = a 1 Δ 2 = 2 ⋅ a 1 + a 2 Δ 3 = 3 ⋅ a 1 + 2 ⋅ a 2 + a 3 Δ 4 = 4 ⋅ a 1 + 3 ⋅ a 2 + 2 ⋅ a 3 + a 4 \begin{array}{l} \Delta_1 = a_1\\ \Delta_2 = 2 \cdot a_1+a_2\\ \Delta_3 = 3 \cdot a_1 + 2 \cdot a_2 + a_3\\ \Delta_4 = 4 \cdot a_1 + 3 \cdot a_2 + 2 \cdot a_3 + a_4\\ \end{array} Δ1=a1Δ2=2a1+a2Δ3=3a1+2a2+a3Δ4=4a1+3a2+2a3+a4

看起来似乎很有规律,发现我们还能再作一次差,那么会得到:

Δ 1 ′ = a 1 Δ 2 ′ = a 1 + a 2 Δ 3 ′ = a 1 + a 2 + a 3 Δ 4 ′ = a 1 + a 2 + a 3 + a 4 \begin{array}{l} \Delta_1' = a_1\\ \Delta_2' = a_1+a_2\\ \Delta_3' = a_1 + a_2 + a_3\\ \Delta_4' = a_1 + a_2 + a_3 + a_4\\ \end{array} Δ1=a1Δ2=a1+a2Δ3=a1+a2+a3Δ4=a1+a2+a3+a4

你会发现,嗯?这不是前缀和吗?

那么结论就是: b b b 数组是 a a a 数组的 k + 1 k+1 k+1 阶前缀和。

当然,这题也可以根据组合数推出来。

C n k = C n − 1 k + C n − 1 k − 1 C_n^k= C_{n-1}^{k}+C_{n-1}^{k-1} Cnk=Cn1k+Cn1k1 即可得
b n , k = ∑ i = 1 n C n − i + 1 k ⋅ a i b n , k = ∑ i = 1 n ( C n − i k + C n − i k − 1 ) ⋅ a i b n , k = b n − 1 , k − 1 + b n − 1 , k \begin{array}{l} b_{n,k}=\sum_{i=1}^{n}C_{n-i+1}^{k}\cdot a_i \\ b_{n,k}= \sum_{i=1}^{n}(C_{n-i}^{k}+C_{n-i}^{k-1})\cdot a_i\\ b_{n,k}= b_{n-1,k-1}+b_{n-1,k} \end{array} bn,k=i=1nCni+1kaibn,k=i=1n(Cnik+Cnik1)aibn,k=bn1,k1+bn1,k

这样,我们开一个二维数组 b n , k b_{n,k} bn,k b n , k b_{n,k} bn,k 就能从之前的状态中推出来了。

当然,这里我们直接暴力做 a a a 数组的 k + 1 k+1 k+1 次前缀和会比较方便一些。

时间复杂度: O ( n k ) O(nk) O(nk)

AC代码:


#include <bits/stdc++.h>
#define YES return void(cout << "Yes\n")
#define NO return void(cout << "No\n")
using namespace std;

using ui64 = unsigned long long;
using PII = pair<int, int>;
using i64 = long long;

const int mod = 998244353;

void solve() {

    i64 n, x, y, m, k;

    cin >> n;
    vector<i64> a(n + 1);
    cin >> a[1] >> x >> y >> m >> k;

    for (int i = 2; i <= n; ++i) {
        a[i] = (a[i - 1] * x + y) % m;
    }

    // k + 1次前缀和
    for (int j = 1; j <= k + 1; ++j) {
        for (int i = 1; i <= n; ++i) {
            a[i] = (a[i] + a[i - 1]) % mod;
        }
    }

    i64 c = 0;
    for (int i = k; i <= n; ++i) {
        c ^= a[i - k + 1] * i;
    }

    cout << c << '\n';
}

signed main() {

    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);

    int t = 1; //cin >> t;
    while (t--) solve();

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柠檬味的橙汁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值