[SDOI2008] 递归数列

题面

一个由自然数组成的数列按下式定义:

对于 ikai=bi

对于 i>kai=j=1kcj×aij

其中 b1kc1k 是给定的自然数。

写一个程序,给定自然数 mn,计算 (i=mnai)modp

1k151mn10180bi,ci109p108

题解

因为 k 很小,n,m 很大,不难想到矩阵加速递推。

根据 ai=j=1kcj×aij,所以我们的矩阵应该至少是一个 1×k 的矩阵,可以列出初始矩阵:

[akak1a2a1]

其下一个转移则为:

[ak+1aka3a2]

根据递推式可以列出转移矩阵:

[c1100c20100cn001]

这样我们就可以在 O(K2logN) 的时间里递推出 an 的值。但是我们回顾题意要求求出的值:

G(n,m)=(i=mnai)modp

我们可以设 Sum(n)=i=1nai ,可以发现:

G(n,m)=Sum(n)Sum(m1)

所以我们可以在矩阵加速的时候一起处理出来 Sum(n),令我们的初始矩阵扩充为:

[akak1a2a1Sum(k1)]

其下一个转移则为:

[ak+1aka3a2Sum(k)]

考虑到 Sum(n)=Sum(n1)+an,可以得到扩充后的转移矩阵为:

[c11001c20100cn10000cn0011]

这样我们就可以在 O(K2logN) 的时间里解决这道题。

Code

//Luogu - P2461
#include<bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;

valueType MOD_;
valueType const &MOD = MOD_;

class Matrix {
public:
    typedef long long valueType;
    typedef valueType &reference;
    typedef size_t sizeType;
    typedef std::vector<valueType> Row;
    typedef std::vector<Row> Container;
    valueType MOD = ::MOD;

    enum TYPE : int {
        EMPTY = 0, UNIT = 1
    };

protected:
    sizeType _row_, _column_;
    Container data;

public:
    Matrix(sizeType row, sizeType column) : _row_(row), _column_(column), data(_row_) {
        for (auto &iter: data)
            iter.resize(column, 0);
    };

    sizeType row() const {
        return _row_;
    }

    sizeType column() const {
        return _column_;
    }

    void set(TYPE type) {
        for (auto &iter: data) {
            std::fill(iter.begin(), iter.end(), 0);
        }

        if (type == EMPTY)
            return;

        if (type == UNIT)
            for (sizeType i = 0, end = std::min(_row_, _column_); i < end; ++i)
                data[i][i] = 1;
    }

    reference operator()(sizeType i, sizeType j) {
        if (i > this->_row_ || j > this->_column_)
            throw std::out_of_range("Too Large.");

        if (i == 0 || j == 0)
            throw std::out_of_range("0 index access.");

        return std::ref(data[i - 1][j - 1]);
    }

    Matrix operator+(const Matrix &T) const {
        if (this->_row_ != T._row_ || this->_column_ != T._column_)
            throw std::range_error("Illegal operation.");

        Matrix result(this->_row_, this->_column_);

        for (sizeType i = 0; i < this->_row_; ++i)
            for (sizeType j = 0; j < this->_column_; ++j)
                result.data[i][j] = (this->data[i][j] + T.data[i][j]) % MOD;

        return result;
    }

    Matrix operator*(const Matrix &T) const {
        if (this->_column_ != T._row_)
            throw std::range_error("Illegal operation.");

        Matrix result(this->_row_, T._column_);

        for (sizeType i = 0; i < this->_row_; ++i) {
            for (sizeType k = 0; k < this->_column_; ++k) {
                valueType r = this->data[i][k];

                for (sizeType j = 0; j < T._column_; ++j)
                    result.data[i][j] = (result.data[i][j] + T.data[k][j] * r) % MOD;
            }
        }

        return result;
    }

    Matrix operator^(valueType x) const {
        if (x < 1)
            throw std::range_error("Illegal operation.");

        Matrix result(this->_row_, this->_column_);
        Matrix base = *this;

        result.set(UNIT);

        while (x) {
            if (x & 1) result = result * base;

            base = base * base;

            x = x >> 1;
        }

        return result;
    }

    friend std::ostream &operator<<(std::ostream &os, const Matrix &T) {
        for (sizeType i = 0; i < T._row_; ++i)
            for (sizeType j = 0; j < T._column_; ++j)
                os << T.data[i][j] << " \n"[j == T._column_ - 1];

        return os;
    }

    friend std::istream &operator>>(std::istream &os, Matrix &T) {
        for (sizeType i = 0; i < T._row_; ++i)
            for (sizeType j = 0; j < T._column_; ++j)
                os >> T.data[i][j];

        return os;
    }
};

int main() {
	valueType K, M, N;
	
	std::cin >> K;
	
	ValueVector B(K + 30, 0), C(K + 30, 0);
	
	for(int i = 1; i <= K; ++i)
		std::cin >> B[i];

	for(int i = 1; i <= K; ++i)
		std::cin >> C[i];

	std::cin >> M >> N >> MOD_;
	
	for(int i = 1; i <= K; ++i) {
		B[i] %= MOD;
		C[i] %= MOD;
	}
	
	Matrix ans(1, K + 1), base(K + 1, K + 1);
	
	ans.set(Matrix::EMPTY);
	base.set(Matrix::EMPTY);
	
	for(int i = 1; i <= K; ++i)
		base(i, 1) = C[i];
		
	for(int i = 2; i <= K; ++i)
		base(i - 1, i) = 1;
		
	base(1, K + 1) = base(K + 1, K + 1) = 1;
	
	for(int i = 1; i <= K; ++i)
		ans(1, K + 1 - i) = B[i];
		
	ans(1, K + 1) = std::accumulate(B.begin() + 1, B.begin() + K, 0) % MOD;
	valueType resultN = 0, resultM = 0;
	
	++N;
	if(N > K) {
		Matrix MatrixN = ans * (base ^ (N - K));
		
		resultN = MatrixN(1, K + 1);
	} else {
		resultN = std::accumulate(B.begin() + 1, B.begin() + N, 0);
	}

	if(M > K) {
		Matrix MatrixM = ans * (base ^ (M - K));
		
		resultM = MatrixM(1, K + 1);
	} else {
		resultM = std::accumulate(B.begin() + 1, B.begin() + M, 0);
	}
	
	valueType result = resultN - resultM;
	
	result = (result % MOD + MOD) % MOD;
	
	std::cout << result << std::flush;
	
	return 0;
}
posted @   User-Unauthorized  阅读(36)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示