UVa 11551 Experienced Endeavour

题目描述

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 101t10),表示测试用例的数量。每个测试用例的格式如下:

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 501n50) 开始,表示 Alice\texttt{Alice}Alice 收到的整数列表的元素个数
  • 整数 rrr (1≤r≤1091 \leq r \leq 10^91r109) 表示这些操作需要重复执行的次数
  • 接下来一行是原列表的非负整数值
  • 然后是 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,xi1]

输出格式

输出包含 ttt 行,每行对应一个测试用例,列出最终的整数列表(每个元素对 100010001000 取模),格式为:

c0 c1 ... cn-1

题目分析

问题本质

这个问题要求我们模拟一个线性变换过程:

  • 给定初始向量 a=[a0,a1,…,an−1]a = [a_0, a_1, \ldots, a_{n-1}]a=[a0,a1,,an1]
  • 每次根据给定的规则生成新的向量
  • 重复这个过程 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),,vn1(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×log⁡r)O(n^3 \times \log r)O(n3×logr)

算法步骤

  1. 读取测试用例数量 ttt
  2. 对于每个测试用例:
    • 读取 nnnrrr
    • 读取初始向量 aaa
    • 构建变换矩阵 MMM
    • 使用矩阵快速幂计算 MrM^rMr
    • 计算 Mr×aM^r \times aMr×a 得到结果向量
    • 输出结果(对 100010001000 取模)

复杂度分析

  • 矩阵乘法:O(n3)O(n^3)O(n3)
  • 矩阵快速幂:O(n3×log⁡r)O(n^3 \times \log r)O(n3×logr)
  • 总复杂度:O(t×n3×log⁡r)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 值过大的问题。这种将重复操作转化为矩阵幂运算的思路在竞赛编程中非常常见,是一个重要的解题技巧。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值