[题解]P5550 |Chino的数列

时间:2019-09-17
本文章向大家介绍[题解]P5550 |Chino的数列,主要包括[题解]P5550 |Chino的数列使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目链接

人生第一道矩乘题,一遍过

分析

对于数据范围进行分析,\(n\) 很小而 \(k\) 很大,可以考虑到矩阵快速幂优化递推

考虑构造一个矩阵来存储 \(a\) 数组,
即:\(A=\left\|a_1,a_2,\cdots,a_n\right\|\)

操作1

我们把数组前移一位,利用矩阵乘法的原理,可以构造出 \(B_1\) 使

\(A*B_1=\left\|a_2,a_3,\cdots,a_n,a_1\right\|\)

如对于样例,\(B_1=\left\|\begin{array}{cc}0&0&0&1\\1&0&0&0\\0&1&0&0&\\0&0&1&0\end{array}\right\|\)

操作2

我们把数组交换两位,利用矩阵乘法的原理,可以构造出 \(B_2\) 使

\(A*B_2=\left\|a_1,a_2,\cdots,a_{s-1},a_m,a_{s+1},\cdots,a_{m-1},a_s,a_{m+1},\cdots,a_n\right\|\)

此时我们只需将单位矩阵中的两列交换即可

如对于样例,\(B_2=\left\|\begin{array}{cc}0&1&0&0\\1&0&0&0\\0&0&1&0&\\0&0&0&1\end{array}\right\|\)

结合

根据矩阵乘法那套理论手玩样例,将 \(B_1\)\(B_2\) 相乘即可得到 \(B=B_1*B_2\)

根据矩阵乘法具有结合律,我可以用快速幂加速矩阵递推,则最终结果为 \(A*B^k\) 的第一行

代码

\(\mathcal{Code:}\)

#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 100010
#define int long long
#define debug cout<<__LINE__<<" "<<__FUNCTION__<<"\n"

inline int read(){
    int x=0,y=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')y=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*y;
}
void put(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>=10) put(x/10);
    putchar((x%10)+48);
}
int n,s,m,t;
struct Martix{
    int c[110][110];
    Martix(){memset(c,0,sizeof c);}
    friend Martix operator * (const Martix &x,const Martix &y){
        Martix res;
        for(int i=1;i<=n;i++)//枚举矩阵1的行 
            for(int j=1;j<=n;j++)//枚举矩阵2的列
                for(int k=1;k<=n;k++)//累加 
                    res.c[i][j]+=x.c[i][k]*y.c[k][j];
        return res;
    }
}ans,a;
inline Martix ksm(Martix a,int b){
    Martix res;
    for(int i=1;i<=n;i++) res.c[i][i]=1;//记得赋单位矩阵 
    while(b){
        if(b&1) res=res*a;
        a=a*a;
        b>>=1;
    }
    return res;
}
signed main(){
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    n=read();s=read();m=read();t=read();
    for(int i=1;i<=n;i++) ans.c[1][i]=read();
    for(int i=1;i<=n;i++){//B1 
        a.c[i%n+1][i]=1;
    }
    swap(a.c[s],a.c[m]);//交换两列 
    //我直接将两个矩阵合并了,两种写法等价 
    ans=ans*ksm(a,t);
    for(int i=1;i<=n;i++) cout<<ans.c[1][i]<<" ";
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

原文地址:https://www.cnblogs.com/end-of-mind/p/11535534.html