[Medium-Hard] AT_arc190_d [ARC190D] Matrix Pow Sum
2025/3/27约 970 字大约 5 分钟
简要题意
给定一个 的方阵 ,若 ,表示 不确定。
给出整数 ,你需要将每个不确定的位置填上一个 的整数得到矩阵 。求全体 的和。答案对 取模。
。
思路
对于 ,求解是平凡的,这里只考虑 的情况。
不妨将每个不确定的位置 看成一个自由元 。先考察 ,则每个位置都是一个多元至多 次的多项式。
考虑每一个单元格的多项式的每一项,应当形如 ,则这一项产生的贡献也应当形如 。这启发我们往 去思考。
直觉告诉你这个 一定是好求的,考虑打表:
F[p_] := Table[Mod[Sum[i ^ k, {i, 1, p - 1}], p], {k, 0, p - 1}]
F[17]
得到 {16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}
,于是做出猜想:
尝试证明这个结论。取模 意义下的某一个原根 ,若 则得到:
否则,,所以 ,证毕。
所以只有形如 的项或常数项才会对答案产生贡献。
先来考虑常数项,这是容易的, 就是答案,然后尝试求出形如 的系数之和。
看起来十分困难,不妨模拟矩阵乘法的过程,分析每一项是如何得到的。
对于 ,我们只有下面的两种方法:
- 。
- 。
对于 ,还有一种方法 。依照这种方法统计系数即可。
时间复杂度 。
代码
#include <bits/stdc++.h>
using namespace std;
int n, mod;
int Add(int x, int y){ return (x + y) >= mod ? (x + y - mod) : (x + y); }
int Sub(int x, int y){ return (x - y) < 0 ? (x - y + mod) : (x - y); }
int Mul(int x, int y){ return 1ll * x * y % mod; }
int fastpow(int x, int y){
int ret = 1;
for(;y;y>>=1,x=Mul(x, x)){ if(y & 1) ret = Mul(ret, x); }
return ret;
}
const int N = 105;
struct Matrix {
int a[N][N];
Matrix(){ memset(a, 0, sizeof(a)); }
int* operator[](int x){ return a[x]; }
void idt(){
for(int i=1;i<=n;i++) a[i][i] = 1;
}
} A, B;
Matrix operator*(Matrix A, Matrix B){
Matrix C;
for(int i=1;i<=n;i++){
for(int k=1;k<=n;k++){
for(int j=1;j<=n;j++) C[i][j] = Add(C[i][j], Mul(A[i][k], B[k][j]));
}
}
return C;
}
Matrix operator^(Matrix A, int k){
Matrix B; B.idt();
while(k){
if(k & 1) B = B * A;
A = A * A, k >>= 1;
}
return B;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
cin >> n >> mod; int cnt = 0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) cin >> A[i][j], cnt += (A[i][j] == 0);
}
if(mod == 2){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) A[i][j] = 1;
}
B = A ^ mod;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) cout << B[i][j] << ' ';
cout << '\n';
}
return 0;
}
B = A ^ mod;
for(int i=1;i<=n;i++){
if(A[i][i]) continue;
for(int j=1;j<=n;j++){
B[i][j] = Add(B[i][j], A[i][j]);
B[j][i] = Add(B[j][i], A[j][i]);
}
}
if(mod == 3){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(A[i][j]) continue;
B[i][j] = Add(B[i][j], A[j][i]);
}
}
}
int tmp = cnt & 1 ? mod - 1 : 1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) cout << Mul(B[i][j], tmp) << ' ';
cout << '\n';
}
return 0;
}
// Written by xiezheyuan