题目描述
Alice\texttt{Alice}Alice 收到 Bob\texttt{Bob}Bob 给出的一个整数列表,需要生成一个新列表,其中新列表的每个元素是原列表中某些整数的和。任务稍微复杂一些,因为 Bob\texttt{Bob}Bob 要求 Alice\texttt{Alice}Alice 重复这个过程多次,然后再给他结果。请你帮助 Alice\texttt{Alice}Alice 自动化这个任务。
输入格式
第一行是 ttt (1≤t≤101 \leq t \leq 101≤t≤10),表示测试用例的数量。每个测试用例的格式如下:
n r
a0 a1 ... an-1
x0 b0,0 b0,1 ... b0,x0-1
x1 b1,0 b1,1 ... b1,x1-1
:
xn-1 bn-1,0 bn-1,1 ... bn-1,xn-1-1
- 每个测试用例以整数 nnn (1≤n≤501 \leq n \leq 501≤n≤50) 开始,表示 Alice\texttt{Alice}Alice 收到的整数列表的元素个数
- 整数 rrr (1≤r≤1091 \leq r \leq 10^91≤r≤109) 表示这些操作需要重复执行的次数
- 接下来一行是原列表的非负整数值
- 然后是 nnn 行,定义 Alice\texttt{Alice}Alice 如何从前一个列表生成新列表
每行的格式为:
xi bi,0 bi,1 ... bi,xi-1
这一行定义了新列表中第 iii 个元素是原列表中以下元素的和:
a[bi,0],a[bi,1],…,a[bi,xi−1]a[b_{i,0}], a[b_{i,1}], \ldots, a[b_{i,xi-1}]a[bi,0],a[bi,1],…,a[bi,xi−1]
输出格式
输出包含 ttt 行,每行对应一个测试用例,列出最终的整数列表(每个元素对 100010001000 取模),格式为:
c0 c1 ... cn-1
题目分析
问题本质
这个问题要求我们模拟一个线性变换过程:
- 给定初始向量 a=[a0,a1,…,an−1]a = [a_0, a_1, \ldots, a_{n-1}]a=[a0,a1,…,an−1]
- 每次根据给定的规则生成新的向量
- 重复这个过程 rrr 次
关键挑战
最直接的思路是模拟 rrr 次变换过程,但是 rrr 的最大值可以达到 10910^9109,如果每次变换都需要 O(n2)O(n^2)O(n2) 的时间复杂度,总时间复杂度将达到 O(n2×r)O(n^2 \times r)O(n2×r),这显然是不可行的。
数学建模
观察变换过程,我们发现每次变换实际上是一个线性变换,可以用矩阵乘法来表示:
设第 kkk 次的向量为 v(k)=[v0(k),v1(k),…,vn−1(k)]Tv^{(k)} = [v_0^{(k)}, v_1^{(k)}, \ldots, v_{n-1}^{(k)}]^Tv(k)=[v0(k),v1(k),…,vn−1(k)]T,那么变换关系可以表示为:
v(k+1)=M×v(k)v^{(k+1)} = M \times v^{(k)}v(k+1)=M×v(k)
其中 MMM 是一个 n×nn \times nn×n 的变换矩阵,M[i][j]=1M[i][j] = 1M[i][j]=1 表示新向量的第 iii 个元素包含原向量第 jjj 个元素,否则为 000。
矩阵快速幂优化
根据线性代数的知识,经过 rrr 次变换后的向量为:
v(r)=Mr×v(0)v^{(r)} = M^r \times v^{(0)}v(r)=Mr×v(0)
其中 v(0)v^{(0)}v(0) 就是初始向量 aaa。
现在问题转化为计算 MrM^rMr,由于 rrr 可能很大 (10910^9109),我们需要使用矩阵快速幂算法,将时间复杂度从 O(n3×r)O(n^3 \times r)O(n3×r) 降低到 O(n3×logr)O(n^3 \times \log r)O(n3×logr)。
算法步骤
- 读取测试用例数量 ttt
- 对于每个测试用例:
- 读取 nnn 和 rrr
- 读取初始向量 aaa
- 构建变换矩阵 MMM
- 使用矩阵快速幂计算 MrM^rMr
- 计算 Mr×aM^r \times aMr×a 得到结果向量
- 输出结果(对 100010001000 取模)
复杂度分析
- 矩阵乘法:O(n3)O(n^3)O(n3)
- 矩阵快速幂:O(n3×logr)O(n^3 \times \log r)O(n3×logr)
- 总复杂度:O(t×n3×logr)O(t \times n^3 \times \log r)O(t×n3×logr),在题目限制下完全可行
代码实现
// Experienced Endeavour
// UVa ID: 11551
// Verdict: Accepted
// Submission Date: 2025-11-19
// UVa Run Time: 0.000s
//
// 版权所有(C)2025,邱秋。metaphysis # yeah dot net
#include <bits/stdc++.h>
using namespace std;
const int MOD = 1000;
typedef vector<int> Vec;
typedef vector<Vec> Mat;
Mat multiply(const Mat &a, const Mat &b) {
int n = a.size();
Mat res(n, Vec(n, 0));
for (int i = 0; i < n; i++)
for (int k = 0; k < n; k++)
if (a[i][k])
for (int j = 0; j < n; j++)
res[i][j] = (res[i][j] + a[i][k] * b[k][j]) % MOD;
return res;
}
Mat power(Mat base, int exp) {
int n = base.size();
Mat res(n, Vec(n, 0));
for (int i = 0; i < n; i++) res[i][i] = 1;
while (exp > 0) {
if (exp & 1) res = multiply(res, base);
base = multiply(base, base);
exp >>= 1;
}
return res;
}
int main() {
int t;
cin >> t;
while (t--) {
int n, r;
cin >> n >> r;
Vec a(n);
for (int i = 0; i < n; i++) cin >> a[i];
Mat trans(n, Vec(n, 0));
for (int i = 0; i < n; i++) {
int x;
cin >> x;
for (int j = 0; j < x; j++) {
int idx;
cin >> idx;
trans[i][idx] = 1;
}
}
Mat transR = power(trans, r);
Vec res(n, 0);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
res[i] = (res[i] + transR[i][j] * a[j]) % MOD;
for (int i = 0; i < n; i++) {
if (i > 0) cout << " ";
cout << res[i];
}
cout << endl;
}
return 0;
}
总结
本题的关键在于识别出变换过程的线性性质,并将其建模为矩阵乘法问题。通过使用矩阵快速幂,我们成功地将指数级的时间复杂度优化为对数级,从而解决了 rrr 值过大的问题。这种将重复操作转化为矩阵幂运算的思路在竞赛编程中非常常见,是一个重要的解题技巧。
262

被折叠的 条评论
为什么被折叠?



