洛谷P3873 [TJOI2010]天气预报

题目

https://www.luogu.com.cn/problem/P3873

思路

线性递推,自然就是矩乘辣(话说省选竟然有这种裸题吗?)。

给个图意思一下吧(以n=5为例):

\[\left[ \begin{matrix} w_1 & w_2 & w_3 & w_4 & w_5\end{matrix} \right]*\left[ \begin{matrix} 0 & 0 & 0 & 0 & a_5\\1 & 0 & 0 & 0 & a_4\\0 & 1 & 0 & 0 & a_3\\0 & 0 & 1 & 0 & a_2\\ 0 & 0 & 0 & 1 &a_1\end{matrix}\right]= \left[ \begin{matrix} w_2 & w_3 & w_4 & w_5 & w_6\end{matrix} \right] \]

那么要求第\(m\)项,把这个操作做\(m-n\)遍就可以了,此时答案矩阵的第1行第\(n\)列元素就是所求的\(w_m\)

众所周知矩乘满足结合律,所以我们把中间的\(n*n\)矩阵拎出来,做个矩阵快速幂,再右乘上原来的\(w\)向量,就可以求出答案矩阵。

代码

#include<cstdio>
#include<cstdlib>
#define maxn 110
#define mod 4147
using namespace std;
int w[maxn],a[maxn],n,m;
struct matrix{
    int d[101][101];
    public:
        void init(){
            int i,j;
            for(i=1;i<=n;++i)
                for(j=1;j<=n;++j)
                    d[i][j]=0;
        }
    matrix operator *(matrix x){
        int i,j,k;
        matrix ans;
        ans.init();
        for(i=1;i<=n;++i)
            for(j=1;j<=n;++j)
                for(k=1;k<=n;++k)
                    ans.d[i][j]=(ans.d[i][j]+d[i][k]*x.d[k][j])%mod;
        return ans;
    }
    
} e;
matrix pow(matrix x,int p){
    matrix ans,base;
    ans=e;base=x;
    while(p){
        if(p&1) ans=ans*base;
        base=base*base;
        p>>=1;
    }
    return ans;
}
int main(){
    int i,j,ans;
    matrix f,x;
    scanf("%d%d",&n,&m);
    for(i=n;i>=1;i--)
        scanf("%d",&w[i]);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    x.init();f.init();e.init();
    for(i=1;i<=n;i++)
        e.d[i][i]=1;
    for(i=1;i<=n;i++)
        x.d[1][i]=w[i];
    for(i=1;i<n;i++)
        f.d[i+1][i]=1;
    for(i=1;i<=n;i++)
        f.d[i][n]=a[n+1-i];
    ans=(x*pow(f,m-n)).d[1][n];
    printf("%d",ans);
    // system("pause");
    return 0;
}
posted @ 2020-12-07 20:16  文艺平衡树  阅读(51)  评论(0编辑  收藏  举报