原题链接: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=(Ck1⋅a1)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=(Ck2⋅a1+Ck1⋅a2)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=(Ck3⋅a1+Ck2⋅a2+Ck1⋅a3)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=1iCki−j+1⋅aj)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=3⋅a1+a2b3=6⋅a2+3⋅a2+a3b4=10⋅a2+6⋅a2+3⋅a3+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=2⋅a1+a2Δ3=3⋅a1+2⋅a2+a3Δ4=4⋅a1+3⋅a2+2⋅a3+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=Cn−1k+Cn−1k−1 即可得
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=1nCn−i+1k⋅aibn,k=∑i=1n(Cn−ik+Cn−ik−1)⋅aibn,k=bn−1,k−1+bn−1,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;
}