P3890 题解
这个方法来自 @realskc。非常感谢 Ta。
首先这个矩阵乘法不满足结合律,不能使用快速幂优化。尝试找一些性质。
因为
把每次矩阵乘法看作
记
接下来给出一个重要结论:对于任意
对于
显然,此时每一类的二进制数表示,加上一个
于是
#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,m,a[N][N],ans[N][N],nxt[2*N],idx,vis[2*N],stk[N],top;
bitset<N> row[N],col[N],all,st[N],buc[2*N];
unordered_map<bitset<N>,int> mp;
int read() {
int x=0,f=1; char c=getchar();
for(;c<'0'||c>'9';c=getchar()) if(c=='-') f=-1;
for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-48;
return x*f;
}
int main() {
n=read(); m=read()-1;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) a[i][j]=read();
if(!m) {
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) printf("%d%c",a[i][j]," \n"[j==n-1]);
return 0;
}
for(int i=0;i<n;i++) all[i]=1;
for(int k=0;k<30;k++) {
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) row[i][j]=col[j][i]=a[i][j]>>k&1;
mp.clear(); idx=0;
mp[all]=0; buc[0]=all; st[0]=all;
for(int i=0;i<n;i++) {
if(mp.find(col[i])==mp.end())
mp[col[i]]=++idx,buc[idx]=col[i],st[idx]=all;
st[mp[col[i]]][i]=0;
}
for(int i=0,ii=idx;i<=ii;i++) {
if(mp.find(st[i])==mp.end())
mp[st[i]]=++idx,buc[idx]=st[i],nxt[idx]=0;
nxt[i]=mp[st[i]];
}
for(int i=0;i<n;i++) {
int x=mp.find(row[i])==mp.end()?0:nxt[mp[row[i]]];
vis[x]=1; stk[++top]=x;
for(int j=2;j<=m;j++) {
x=nxt[x];
if(!vis[x]) {vis[x]=j; stk[++top]=x; continue;}
x=stk[vis[x]+(m-j)%(j-vis[x])]; break;
}
while(top) vis[stk[top--]]=0;
for(int j=0;j<n;j++) ans[i][j]|=buc[x][j]<<k;
}
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++) printf("%d%c",ans[i][j]," \n"[j==n-1]);
return 0;
}
值得一提的是,如果对整个矩阵找循环节而非行向量,进入循环的时间可能非常大。2023.12.20 及以前的所有提交均是错解,第