矩阵经典题目四:送给圣诞夜的礼品(使用m个置换实现对序列的转变)

时间:2023-03-08 16:44:34

https://vijos.org/p/1049

给出一个序列,含n个数。然后是m个置换,求对初始序列依次进行k次置换,求最后的序列。



先看一个置换。把置换表示成矩阵的形式。然后将m个置换乘起来。那么初始序列首先运行这个置换k/m次。然后顺次运行前k%m个置换,最后乘上初始矩阵。

最后注意矩阵乘法的顺序。A*B != B*A。



#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-12
#define PI acos(-1.0)
#define C 240
#define S 20
using namespace std; const int maxn = 110; struct matrix
{
int mat[maxn][maxn];
int n,m;
void init()
{
memset(mat,0,sizeof(mat));
for(int i = 1; i <= 105; i++)
{
mat[i][i] = 1;
}
}
}M[11]; //将每个置换表示出来。 int n,m; matrix mul(matrix a, matrix b)
{
matrix ans;
memset(ans.mat,0,sizeof(ans.mat));
ans.n = a.n;
ans.m = b.m;
for(int i = 1; i <= a.n ; i++)
{
for(int k = 1; k <= a.m; k++)
{
if(a.mat[i][k] == 0) continue;
for(int j = 1; j <= b.m; j++)
ans.mat[i][j] += a.mat[i][k]*b.mat[k][j];
}
}
return ans;
} matrix pow(matrix a, int n)
{
matrix ans;
ans.n = a.n;
ans.m = a.m;
ans.init(); while(n)
{
if(n&1)
ans = mul(ans,a);
a = mul(a,a);
n >>= 1;
}
return ans;
} int main()
{
int num,k,z;
while(~scanf("%d %d %d",&n,&m,&k))
{
matrix a,b;
a.init();
a.m = a.n = n;
b.n = n;
b.m = 1;
for(int i = 1; i <= n; i++)
b.mat[i][1] = i; for(int i = 1; i <= m; i++)
{
memset(M[i].mat,0,sizeof(M[i].mat));
M[i].m = M[i].n = n;
for(int j = 1; j <= n; j++)
{
scanf("%d",&num);
M[i].mat[j][num] = 1;
}
a = mul(M[i],a); //注意相乘的顺序
} z = k/m;
k = k%m; a = pow(a,z);
for(int i = 1; i <= k; i++)
a = mul(M[i],a);//注意相乘的顺序
a = mul(a,b);
for(int i = 1; i <= n; i++)
{
printf("%d",a.mat[i][1]);
if(i == n)
printf("\n");
else printf(" ");
}
}
return 0;
}