P8110 [Cnoi2021] 矩阵题解

前言

这篇题解可能有点啰嗦,个人还是觉得比较通俗易懂的。

这道题可能会用到点矩阵的知识,没学过矩阵的可以参考我的这篇博客:

【矩阵浅谈】

题意:

给你两个序列 \(\{a_n\},\{b_n\}\)

告诉你一个矩阵 \(A\) 是满足 \(A_{i,j} = a_i \times b_j\) 的。

\(A^k\) 中所以元素的和。

思路:

看到数据范围 \(n \le 10^5\) 和题目背景中的:

Rumia 喜欢矩阵快速幂,而 Cirno 觉得这是平凡的。

能推出这题不是矩阵快速幂的板子,而是一个考虑两个数组对于这个矩阵的贡献的问题。

我们从样例 \(1\) 入手:

3 0
1 2 3
4 5 6

我们可以得到 \(A\) 矩阵为:

{4 5 6}         = {1 × 4, 1 × 5, 1 × 6}
{8 10 12}       = {2 × 4, 2 × 5, 2 × 6}
{12 15 18}      = {3 × 4, 3 × 5, 3 × 6}

发现 \(2\) 个序列中每个点都有 \(3\) 处贡献。

我们再考虑这个式子的实际意义:

就是 \(a\) 序列中每个点都对应着 \(b\) 序列中的每一个点。

所以说 \(a\) 序列和 \(b\) 序列中的每个点都会对原矩阵做出 \(n\) 次贡献。

这个时候我们只考虑了序列对于矩阵 \(A\) 的贡献,而不知道对于 \(A^k\) 的贡献。

我们再来考虑矩阵乘法的式子的意义:

\[C_{i,j} = \sum_{r=1}^{b} A_{i,r} \times B_{r, j} \]

而这里 \(A\) 矩阵和 \(B\) 矩阵相同。

所以可以转化为:

\[C_{i,j} = \sum_{r=1}^{b} A_{i,r} \times A_{r, j} \]

比如说:
矩阵的第一行:
c[1][1] = a[1][1] × a[1][1] + a[1][2] × a[2][1] + a[1][3] × a[3][1];
c[1][2] = a[1][1] × a[1][2] + a[1][2] × a[2][2] + a[1][3] × a[3][2];
c[1][3] = a[1][1] × a[1][3] + a[1][2] × a[2][3] + a[1][3] × a[3][3];
我们对于矩阵的第一行求和:
sum1 = c[1][1] + c[1][2] + c[1][3]
	= a[1][1] × (a[1][1] + a[1][2] + a[1][3]) + a[1][2] × (a[2][1] + a[2][2] + a[2][3]) + a[1][3] × (a[3][1] + a[3][2] + a[3][3])。

可能光看第一行你还不知道有什么规律,我再把第二行都列出来:

矩阵的第二行:
c[2][1] = a[2][1] × a[1][1] + a[2][2] × a[2][1] + a[2][3] × a[3][1];
c[2][2] = a[2][1] × a[1][2] + a[2][2] × a[2][2] + a[2][3] × a[3][2];
c[2][3] = a[2][1] × a[1][3] + a[2][2] × a[2][3] + a[2][3] × a[3][3];
sum2 = c[2][1] + c[2][2] + c[2][3]
    = a[2][1] × (a[1][1] + a[1][2] + a[1][3]) + a[2][2] × (a[2][1] + a[2][2] + a[2][3]) + a[2][3] × (a[3][1] + a[3][2] + a[3][3]);

第三行:

矩阵的第三行:
c[3][1] = a[3][1] × a[1][1] + a[3][2] × a[2][1] + a[3][3] × a[3][1];
c[3][2] = a[3][1] × a[1][2] + a[3][2] × a[2][2] + a[3][3] × a[3][2];
c[3][3] = a[3][1] × a[1][3] + a[3][2] × a[2][3] + a[3][3] × a[3][3];
sum2 = c[3][1] + c[3][2] + c[3][3]
    = a[3][1] × (a[1][1] + a[1][2] + a[1][3]) + a[3][2] × (a[2][1] + a[2][2] + a[2][3]) + a[3][3] × (a[3][1] + a[3][2] + a[3][3]);

根据上述三行可知:

矩阵的元素总和为:
 Sum = sum1 +sum2 + sum3 
     = (a[1][1] + a[1][2] + a[1][3]) × (a[1][1] + a[2][1] + a[3][1]) + (a[2][1] + a[2][2] + a[2][3]) × (a[1][2] + a[2][2] + a[3][2]) + (a[3][1] + a[3][2] + a[3][3]) × (a[1][3] + a[2][3] + a[3][3])。

从这个式子我们可以看出一个结论:

一个矩阵自乘后矩阵元素的总和,就是他的第 \(n\) 行乘第 \(n\) 列的和。

我们再根据之前得出的结论:

这个矩阵中 \(a\) 序列和 \(b\) 序列中的每个点都会对原矩阵做出 \(n\) 次贡献。

如果我们要算出矩阵 \(A\) 后在求,算矩阵 \(A\) 的复杂度为 \(\mathcal{O}(n^2)\),因为对于每个 \(a\) 序列里的数都要扫一遍 \(b\) 序列,所以这题我们要直接考虑 \(a\) 序列和 \(b\) 序列对于矩阵的贡献。

根据这两个结论推得:

\[ans = \sum{a_{i}} \times \sum b_i \times (\sum a_i \times b_i)^{k- 1}\]

AC code:

/*
work by: TLE_Automation
Time: O(轻轻松松过)
knowledge: 垃圾算法
*/
#include<bits/stdc++.h>
#define int long long
#define orz cout << "szt lps fjh AK IOI";
using namespace std;

const int INF = 1e9 + 7;
const int mod = 998244353;
const int maxn = 2e5 + 10;
const int MAXN = 3e3 + 10;

inline int read() {
   int s = 0, w = 1;
   char ch = getchar();
   while (!isdigit(ch)) {if(ch == '-') {w = -1;}ch = getchar();}
   while (isdigit(ch)) {s = (s << 1) + (s << 3) + (ch ^ 48);ch = getchar();}
   return s * w;
}

inline void print(int x) {
   if (x < 0 ) putchar('-'), x = -x;
   if (x > 9 ) print(x / 10);
   putchar(x % 10 + '0');
}

int n, k, a[maxn], b[maxn];
 
int ksm(int a, int b) {
	int res = 1, base = a;
	while(b) {
		if(b & 1) res = (res * base) % mod;
		base = (base * base) % mod, b >>= 1;
	}return res;
}

int ans = 1;
int sum = 0;
int ans1 = 0, ans2 = 0;
signed main() {
	n = read(), k = read();
	if(k == 0) return print(n), 0;
	for(int i = 1; i <= n; i++) a[i] = read(), ans1 = (ans1 + a[i]) % mod;
	for(int i = 1; i <= n; i++) b[i] = read(), ans2 = (ans2 + b[i]) % mod;	
	for(int i = 1; i <= n; i++) {
		sum = (sum + a[i] * b[i]) % mod;
	}
	ans1 %= mod, ans2 %= mod;
	ans = (((ans1 % mod * ans2 % mod) % mod) * ksm(sum, k - 1) % mod + mod) %mod; 
	print(ans % mod);
}
posted @ 2022-05-20 20:01  TLE_Automation  阅读(27)  评论(0编辑  收藏  举报