用矩阵求解线性递推式通项

用fft优化矩阵乘法

首先把递推式求解转化为矩阵求幂,再利用特征多项式f(λ)满足f(A) = 0,将矩阵求幂转化为多项式相乘,

最后利用傅里叶变换的高效算法(迭代取代递归)(参见算法导论)解决。

 #include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
#include <vector>
#include <set>
#include <cmath>
#include <ctime>
#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
#define lson (u << 1)
#define rson (u << 1 | 1)
typedef long long ll;
const double eps = 1e-;
const double pi = acos(-1.0);
const int maxn = 4e4 + ;
const int maxm = ;
const int mod = ;
const int inf = 0x3f3f3f3f; int n, a, b, p, q;
int size;
int f[maxn], g[maxn]; struct Complex{
double ii, ij;//ii::real, ij::image
Complex(double ii = , double ij = ) : ii(ii), ij(ij) {}
// Complex clear() { this->ii = this->ij = 0; }
Complex operator + (const Complex &rhs) const{
return Complex(ii + rhs.ii, ij + rhs.ij);
}
Complex operator - (const Complex &rhs) const{
return Complex(ii - rhs.ii, ij - rhs.ij);
}
Complex operator * (const Complex &rhs) const{
return Complex(ii * rhs.ii - ij * rhs.ij, ii * rhs.ij + ij * rhs.ii);
}
}; Complex a1[maxn], a2[maxn]; void fft(Complex *src, int len, int rev){
//len is power of 2
//rev == 1::dft rev == -1::idft
for(int i = , j = ; i < len; i++){
for(int k = len >> ; k > (j ^= k); k >>= ) ;
if(i < j) swap(src[i], src[j]);
}
for(int i = ; i <= len; i <<= ){
Complex wi(cos( * pi * rev / i), sin( * pi * rev / i));
//(wi)^i = 1
for(int j = ; j < len; j += i){
//using iteration insetad of recursion
Complex w(1.0, 0.0);
//w = (wi)^0
for(int k = j; k < j + i / ; k++){
Complex tem = w * src[k + i / ];
src[k + i / ] = src[k] - tem;
src[k] = src[k] + tem;
w = w * wi;
}
}
}
if(rev == -){
for(int i = ; i < len; i++) src[i].ii = (src[i].ii / len + eps);
}
} void multi(int *src1, int *src2, int len){
for(int i = ; i < len; i++){
a1[i].ii = a1[i].ij = a2[i].ii = a2[i].ij = ;
if(i < q){
a1[i].ii = (double)src1[i];
a2[i].ii = (double)src2[i];
}
}
fft(a1, len, ), fft(a2, len, );
for(int i = ; i < len; i++) a1[i] = a1[i] * a2[i];
fft(a1, len, -);
for(int i = ; i < len; i++) g[i] = (int)((ll)(a1[i].ii + eps) % mod);
for(int i = * q - ; i >= q; i--){
//this is because for the fisrt row in matrix A,
//which satisfies ths (f(n + q),...,f(n))T = A((f(n + q - 1),...,f(n - 1))T)
//only two elements are nonzero integers
g[i - q] = (g[i - q] + g[i] * b) % mod;
g[i - p] = (g[i - p] + g[i] * a) % mod;
}
memcpy(src1, g, sizeof(int) * q);
} int tmp[maxn], ans[maxn]; int main(){
//freopen("in.txt", "r", stdin);
while(~scanf("%d%d%d%d%d", &n, &a, &b, &p, &q)){
a %= mod, b %= mod;
f[] = ;
for(int i = ; i < q; i++){
f[i] = i < p ? a + b : a * f[i - p] + b;
f[i] %= mod;
}
if(n < q){
printf("%d\n", f[n]);
continue;
}
size = ;
while(size <= (q - ) * ) size <<= ;
memset(tmp, , sizeof tmp);
memset(ans, , sizeof ans);
ans[] = tmp[] = ;
while(n){
if(n & ) multi(ans, tmp, size);
multi(tmp, tmp, size);
n >>= ;
}
int res = ;
for(int i = ; i < q; i++){
res = (res + ans[i] * f[i]) % mod;
}
printf("%d\n", res);
}
return ;
}

hdu4914 Linear recursive sequence的更多相关文章

  1. HDU 4914 Linear recursive sequence(矩阵乘法递推的优化)

    题解见X姐的论文 矩阵乘法递推的优化.仅仅是mark一下. .

  2. hdu 5950 Recursive sequence 矩阵快速幂

    Recursive sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  3. HDU 5950 Recursive sequence 【递推+矩阵快速幂】 (2016ACM/ICPC亚洲区沈阳站)

    Recursive sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  4. CF1106F Lunar New Year and a Recursive Sequence

    题目链接:CF1106F Lunar New Year and a Recursive Sequence 大意:已知\(f_1,f_2,\cdots,f_{k-1}\)和\(b_1,b_2,\cdot ...

  5. HDU 5950 Recursive sequence(矩阵快速幂)

    题目链接:Recursive sequence 题意:给出前两项和递推式,求第n项的值. 题解:递推式为:$F[i]=F[i-1]+2*f[i-2]+i^4$ 主要问题是$i^4$处理,容易想到用矩阵 ...

  6. HDU5950 Recursive sequence (矩阵快速幂)

    Recursive sequence Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Other ...

  7. Codeforces 1106F Lunar New Year and a Recursive Sequence | BSGS/exgcd/矩阵乘法

    我诈尸啦! 高三退役选手好不容易抛弃天利和金考卷打场CF,结果打得和shi一样--还因为queue太长而unrated了!一个学期不敲代码实在是忘干净了-- 没分该没分,考题还是要订正的 =v= 欢迎 ...

  8. HDU5950 Recursive sequence (矩阵快速幂加速递推) (2016ACM/ICPC亚洲赛区沈阳站 Problem C)

    题目链接:传送门 题目: Recursive sequence Time Limit: / MS (Java/Others) Memory Limit: / K (Java/Others) Total ...

  9. HDU5950 Recursive sequence 非线性递推式 矩阵快速幂

    题目传送门 题目描述:给出一个数列的第一项和第二项,计算第n项. 递推式是 f(n)=f(n-1)+2*f(n-2)+n^4. 由于n很大,所以肯定是矩阵快速幂的题目,但是矩阵快速幂只能解决线性的问题 ...

随机推荐

  1. 理解JDBC和JNDI

    下面的英文是我找过来的,因为是英文所以不敢翻译出来误导别人,但是它描述的确实恰到好处,比所谓网上的JNDI和JDBC云云的解释要精辟很多,如果遇到不认识的单词,用有道吧~~:) The Java Na ...

  2. IOS 加载Xib 后 如何 动态修改xib中的控件frame

    看看xib里view是不是设置了自动布局 use auto layout.取消掉就可以了.

  3. Codeforce Round #228 Div2

    这次的A题没注意要到100- -, B题没做,后来做要注意下1和long long C题当时坑的一B,用了个蠢办法,后来还错了,现在改了,还是蠢办法,等等再去用dp吧,而且本来就只有01用个鸡巴的树状 ...

  4. Eclipse安装Ruby插件应该注意的几点

    http://www.aptana.com/products/studio3/success_plugin.html Installing via Eclipse Please copy the fo ...

  5. Extjs treePanel 后台Json的两种构建方法

    public string json = ""; public string QueryMenuTreeJson(string ParentID, string userId) { ...

  6. c++之路起航——指针

    c++一阶指针 定义 存储类型名 数据类型 * 指针变量名: Eg:int *a://定义了一个指向整型的指针 a: 指针使用方法 int a,*b; b=&a;//表明将a的地址赋值给b: ...

  7. yii框架中保存第三方登录信息

    (第三方登录) 创建应用,域名,详情请看:http://www.cnblogs.com/xujn/p/5287157.html 效果图:

  8. ligerui+json_001_实现表格(grid)的后台数据显示、分页

    代码下载地址: http://download.csdn.net/detail/poiuy1991719/8556841 效果: 需要导入的包: 01:编写界面:index.jsp <%@ pa ...

  9. struts_19_对Action中所有方法、某一个方法进行输入校验(手工编写代码实现输入校验)

    对所有方法进行校验1.通过手工编写代码的形式实现 需求:用户名:不能为空手机号:不能为空,并且要符合手机号的格式1,3/5/8,后面是9个数字 第01步:导包 第02步:配置web.xml <? ...

  10. js高级程序设计笔记之-addEventListener()与removeEventListener(),事件解除与绑定

    js高级程序设计笔记之-addEventListener()与removeEventListener(),事件解除与绑定 addEventListener()与removeEventListener( ...