矩阵十大经典题目之四- VOJ1049-送给圣诞夜的礼品

本文探讨了一种处理序列置换问题的高效算法,通过快速幂取模和矩阵乘法优化,实现序列在多次置换后的状态。算法适用于大规模数据处理,特别在需要频繁更新序列的情况下表现优异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://vijos.org/p/1049

题目大意: 顺次给出m个置换,反复使用这m个置换对初始序列进行操作,问k次置换后的序列。m<=10, k<2^31。

注意:

在写矩阵的乘法的时候一定要注意,写好到底是谁乘以谁。写反了就悲剧了。

还有,在求快速幂取模的时候要用非递归写法,不然容易RE;

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
#define Nnum 31
#define Mnum 31
#define LL long long
struct matrix
{
    int n,m;
    int mat[101][101];
    matrix()
    {
        memset(mat,0,sizeof(mat));
    }
    matrix operator+(const matrix& B)const
    {
        int i,j;
        matrix A;
        A.n=n;
        A.m=m;
        for(i=1; i<=n; i++)
            for(j=1; j<=m; j++)A.mat[i][j]=mat[i][j]+B.mat[i][j];
        return A;
    }
}M[11];
matrix mul(matrix A,matrix B)
{
    int i,j,k,nn,mm;
    matrix C;
    nn=A.n;
    mm=B.m;
    C.m=mm;
    C.n=nn;
    for(i=1; i<=nn; i++)
    {
        for(j=1; j<=mm; j++)
        {
            C.mat[i][j]=0;
            for(k=1; k<=A.m; k++)
            {
                C.mat[i][j]+=A.mat[i][k]*(B.mat[k][j]);
            }
        }
    }
    return C;
}
matrix powmul(matrix A,int k)
{
    matrix B;
    B.n=A.n;
    B.m=A.m;
    for(int i=1; i<=min(B.n,B.m); i++)B.mat[i][i]=1;
    while(k>=1)
    {
        if(k&1)B=mul(A,B);
        A=mul(A,A);
        k=k/2;
    }
    return B;
}
int main()
{
    int i,j,n,m,k,a;
    scanf("%d%d%d",&n,&m,&k);
    memset(M,0,sizeof(M));
    matrix A;
    matrix ans;
    A.n=A.m=n;
    ans.n=n;
    ans.m=1;
    for(i=1; i<=n; i++)A.mat[i][i]=1,ans.mat[i][1]=i;
    for(i=1; i<=m; i++)
    {
        M[i].n=M[i].m=n;
        for(j=1; j<=n; j++)
        {
            scanf("%d",&a);
            M[i].mat[j][a]=1;
        }
        A=mul(M[i],A);
    }
    int num=k/m;
    k=k%m;
    A=powmul(A,num);
    for(i=1; i<=k; i++)A=mul(M[i],A);
    A=mul(A,ans);
    for(i=1; i<=n; i++)
    {
        if(i!=1)cout<<" ";
        cout<<A.mat[i][1];
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值