首页 > 其他分享 >[SDOI2008] 递归数列

[SDOI2008] 递归数列

时间:2023-06-14 17:33:33浏览次数:49  
标签:std sizeType Matrix 数列 递归 column result SDOI2008 row

题面

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

对于 \(i \le k\):\(a_{i}= b_{i}\)。

对于 \(i > k\):\(\displaystyle a_{i}= \sum_{j=1}^{k}{c_{j} \times a_{i-j}}\)。

其中 \(b_{1\dots k}\) 和 \(c_{1\dots k}\) 是给定的自然数。

写一个程序,给定自然数 \(m \le n\),计算 \(\left( \sum_{i=m}^{n}{a_{i}} \right) \bmod p\)。

\(1 \le k \le 15\),\(1 \le m \le n \le 10^{18}\),\(0 \le b_{i},c_{i} \le 10^{9}\),\(p \le 10^{8}\)。

题解

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

根据 \(\displaystyle a_{i}= \sum_{j=1}^{k}{c_{j} \times a_{i-j}}\),所以我们的矩阵应该至少是一个 \(1 \times k\) 的矩阵,可以列出初始矩阵:

\[\begin{bmatrix} a_k & a_{k - 1} & \cdots & a_2 & a_1 \end{bmatrix}\]

其下一个转移则为:

\[\begin{bmatrix} a_{k + 1} & a_{k} & \cdots & a_3 & a_2 \end{bmatrix}\]

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

\[\begin{bmatrix} c_1 & 1 & 0 & \cdots & 0\\ c_2 & 0 & 1 & \cdots & 0\\ \vdots & \vdots & \vdots & \ddots & 0\\ c_n & 0 & 0 & \cdots & 1 \end{bmatrix}\]

这样我们就可以在 \(\displaystyle \mathcal{O}(K^2logN)\) 的时间里递推出 \(a_n\) 的值。但是我们回顾题意要求求出的值:

\[G(n, m) = \left( \sum_{i=m}^{n}{a_{i}} \right) \bmod p \]

我们可以设 \(\displaystyle Sum(n) = \sum_{i = 1}^{n}a_i\) ,可以发现:

\[G(n, m) = Sum(n) - Sum(m - 1) \]

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

\[\begin{bmatrix} a_k & a_{k - 1} & \cdots & a_2 & a_1 & Sum(k - 1) \end{bmatrix}\]

其下一个转移则为:

\[\begin{bmatrix} a_{k + 1} & a_{k} & \cdots & a_3 & a_2 & Sum(k) \end{bmatrix}\]

考虑到 \(Sum(n) = Sum(n - 1) + a_n\),可以得到扩充后的转移矩阵为:

\[\begin{bmatrix} c_1 & 1 & 0 & \cdots & 0 & 1\\ c_2 & 0 & 1 & \cdots & 0 & 0\\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots\\ c_{n - 1} & 0 & 0 & \cdots & 0 & 0\\ c_n & 0 & 0 & \cdots & 1 & 1 \end{bmatrix}\]

这样我们就可以在 \(\displaystyle \mathcal{O}(K^2logN)\) 的时间里解决这道题。

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;
}

标签:std,sizeType,Matrix,数列,递归,column,result,SDOI2008,row
From: https://www.cnblogs.com/User-Unauthorized/p/17480901.html

相关文章

  • JAVA非递归生成无限级菜单树的较简代码实现。(非泛用型工具包,仅总结逻辑)
    这是一个根据列表生成一个树状结构的较简单实现。搜了搜看起来好像没多少人总结过这种实现。写上来整理一下自己的思路,请大家用用看看,应该用起来问题不大?反正我没遇到BUG。实现的时间复杂度为O(N),空间复杂度应该还是O(N)吧。不过GPT说O(1)可能是因为java的对象实现hash链表是引用而不是......
  • 二叉树看递归问题(下)
    112. 路径总和112.路径总和-力扣(Leetcode)给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。叶子节点 是指没有子......
  • 算法题:求解斐波那契数列
    概念:斐波那契数列是指以0,1开始,之后每一项都等于前两项之和的数列,即:0,1,1,2,3,5,8,13,21,34,55,89,144……以此类推。这个数列最早是由13世纪意大利数学家斐波那契提出的,并在数学、自然科学和计算机科学等领域有着广泛的应用。题目:若有一只兔子,它每个月生一只小兔子,而小兔子......
  • C语言编程—递归
    递归指的是在函数的定义中使用函数自身的方法。举个例子:从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?"从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?'从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?……'"语......
  • 递归、分治、动态规划、贪心、回溯、分支限界
    递归、分治、动态规划、贪心、回溯、分支限界 相似算法比较:递归、分治、动态规划、贪心、回溯、分支限界​ 在学习算法的过程中,递归、分治、动态规划、贪心、回溯、分支限界这些算法有些类似,都是为了解决大问题,都是把大问题拆分成小问题来解决,但她们之间还是有一些不同之......
  • 等差数列
    题目:/***等差数列:*求等差数列前N项的级数之和。不考虑不合理的输入等特殊情况*输入N,首项M,差值K,整型,空格分隔。*/解答:classTest93{publicstaticvoidmain(String[]args){Scannerinput=newScanner(System.in);//codehere......
  • Luogu P1939 【模板】矩阵加速(数列)
    【模板】矩阵加速(数列)题目描述已知一个数列\(a\),它满足:\[a_x=\begin{cases}1&x\in\{1,2,3\}\\a_{x-1}+a_{x-3}&x\geq4\end{cases}\]求\(a\)数列的第\(n\)项对\(10^9+7\)取余的值。输入格式第一行一个整数\(T\),表示询问个数。以下\(T\)行,每行一个正......
  • Python递归法计算棋盘上所有路径总奖品最大值(京东2016编程题)
    问题描述:假设有一个6x6的棋盘,每个格子里有一个奖品(每个奖品的价值在100到1000之间),现在要求从左上角开始到右下角结束,每次只能往右或往下走一个格子,所经过的格子里的奖品归自己所有。问最多能收集价值多少的奖品。思路:每个格子所在路径的总奖品最大值依赖于左边的格子或右边的格子。......
  • 计算斐波那契数列的前 N 项
    它使用C++11中的多线程库thread来并行计算斐波那契数列的前N项:#include<iostream>#include<thread>#include<vector>voidfib(std::vector<int>&fib,intstart,intend){for(inti=start+2;i<end;i++){fib[i]=fib[i-1]+......
  • 递归-二叉搜索树-leetcode98验证二叉搜索树
    //leetcodesubmitregionbegin(Prohibitmodificationanddeletion)/***Definitionforabinarytreenode.*publicclassTreeNode{*intval;*TreeNodeleft;*TreeNoderight;*TreeNode(){}*TreeNode(intval){this.val=......