一道经典的矩阵乘法题目,将m个置换相乘,然后使用矩阵快速幂求出执行(k / m)次后的矩阵,对于剩下的几项模拟即可。
如下图,相乘一次就等价于将1 2 3 4置换为3 1 2 4
但是在代码实现的时候由于矩阵乘法不满足交换率,需要将矩阵颠倒一下,便于使用快速幂。
代码:
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 100 + 10;
const int maxm = 15;
struct Matrix
{
int v[maxn][maxn];
int x,y;
Matrix()
{
memset(v,0,sizeof(v));
x = y = 0;
}
};
Matrix R,p;
Matrix op[maxm];
int n,m,k;
void init()
{
freopen("vijos1049.in","r",stdin);
freopen("vijos1049.out","w",stdout);
}
Matrix mtMul(Matrix A,Matrix B)
{
if(!A.x || !A.y)return B;
Matrix C;
C.x = A.x;C.y = B.y;
for(int i = 1;i <= A.x;i++)
{
for(int j = 1;j <= B.y;j++)
{
for(int k = 1;k <= A.y;k++)
{
C.v[i][j] += A.v[i][k] * B.v[k][j];
}
}
}
return C;
}
void readdata()
{
scanf("%d%d%d",&n,&m,&k);
for(int i = 1;i <= n;i++)R.v[1][i] = i;
R.x = 1;R.y = n;
p.x = n;p.y = n;
for(int i = 1;i <= m;i++)
{
op[i].x = op[i].y = n;
for(int j = 1;j <= n;j++)
{
int tmp;
scanf("%d",&tmp);
op[i].v[tmp][j] = 1;
}
if(i == 1)p = op[i];
else p = mtMul(p,op[i]);
}
}
Matrix mtPow(Matrix A,int k)
{
if(k == 1)return A;
Matrix ans;
while(k)
{
if(k & 1)ans = mtMul(ans,A);
k >>= 1;
A = mtMul(A,A);
}
return ans;
}
void solve()
{
int g = k / m,h = k % m;
Matrix t = mtPow(p,g);
for(int i = 1;i <= h;i++)t = mtMul(t,op[i]);
R = mtMul(R,t);
for(int i = 1;i < n;i++)
{
printf("%d ",R.v[1][i]);
}
printf("%d\n",R.v[1][n]);
}
int main()
{
init();
readdata();
solve();
return 0;
}