bzoj 3657 斐波那契数列(fib.cpp/pas/c/in/out)

空间 512M  时限2s

【题目描述】

有n个大于1的正整数a1,a2,…,an,我们知道斐波那契数列的递推式是f(i)=f(i-1)+f(i-2),现在我们修改这个递推式变为f(i)=f(i-1)+f(i-2)+r(i-1),其中r(x)为a1,a2,…,an中为x的约数的个数。现在要求f(m) mod 19940417的值。注:初值f(1)=1,f(2)=1

输入格式:

第一行两个数n,m。

接下来一行n个正整数a1,a2,…,an。

输出格式:

输出一行仅一个数,f(m) mod 19940417的值。

样例输入:

3 7

2 2 3

样例输出:

33

数据范围:

30%的数据n<=1000,m<=1000

另外20%的数据 n=0,m<=109

100%的数据n<=100000,m<=109,2<=ai<=109

题解:

  对于100%的数据,我们可以先考虑把fib[i]=fib[i-1]+fib[i-2] 的答案先用矩阵快速幂跑出来。然后依次输入ai,来看每个ai对fib[m]的影响,因为fib(i)=fib(i-1)+fib(i-2)+r(i-1),所以每一个ai,在它k倍(k*ai<=M)的地方的斐波那契值都会产生+1的影响。我们考虑如果对于斐波那契数列的第i项我们对它加一个1并且继续进行后面的递推的话,那么第j项(j>i)的值就是fib[j]+fib[j-i+1]。所以实际上我们可以对于每个ai分别处理,对于ai,它会给最后的答案贡献fib[m mod ai]+fib[ai+(m mod ai)]+…保证[]内的值小于等于m。

  但如果只是一个一个让答案加上fib[k*ai+(m%ai)],还是会超时,肯定要用到矩阵快速幂来优化,假设我们让B为表示fib[m%ai]的矩阵,那么f[k*ai+(m%ai)]可以表示为B*A^k*ai,然后解决的就是SUM = (A + A^2 + A^3 + ... + A^B)%C的问题(讲解)。

 1 #include <cstdio>
 2 #include <algorithm>
 3 using namespace std;
 4 typedef long long LL;
 5 const int mod=19940417;
 6 struct mat {
 7     int a,b,c,d;
 8 }ZR,E,F,Ans;
 9 int n,m;
10 mat pre[33],pw[33];
11 mat operator*(mat X,mat Y) {
12     mat Z;
13     Z.a=((LL)X.a*Y.a+(LL)X.b*Y.c)%mod;
14     Z.b=((LL)X.a*Y.b+(LL)X.b*Y.d)%mod;
15     Z.c=((LL)X.c*Y.a+(LL)X.d*Y.c)%mod;
16     Z.d=((LL)X.c*Y.b+(LL)X.d*Y.d)%mod;
17     return Z;
18 }
19 mat operator+(mat X,mat Y) {
20     mat Z;
21     Z.a=(X.a+Y.a)%mod;
22     Z.b=(X.b+Y.b)%mod;
23     Z.c=(X.c+Y.c)%mod;
24     Z.d=(X.d+Y.d)%mod;
25     return Z;
26 }
27 mat fpm(mat a,int b) {
28     mat w=E;
29     while(b){
30         if(b&1) w=w*a;
31         a=a*a;
32         b>>=1;
33     }
34     return w;
35 }
36 mat vsum(int n){
37     if(n==0) return ZR;
38     if(n==1) return E;
39     int m=1,t=0;
40     while(m<=n) m<<=1,++t;
41     m>>=1,--t;
42     return pre[t]+pw[t]*vsum(n-m);
43 }
44 void prepare(mat A){//A矩阵是系数矩阵的ai次方
45     for(int i=0;i<=30;++i){
46         if(i==0) pw[i]=A;
47         else pw[i]=pw[i-1]*pw[i-1];
48         if(i==0) pre[i]=E;//单位矩阵
49         else pre[i]=pre[i-1]*(E+pw[i-1]);
50     }
51 }
52 mat solve(int d) {
53     if(d>=m) return ZR;
54     int k=(m-1)/d;
55     prepare(fpm(F,d));
56     return fpm(F,m-1-k*d)*vsum(k);
57 }
58 int main() {
59 //    freopen("fib.in" , "r", stdin);
60 //    freopen("fib.out", "w", stdout);
61     scanf("%d%d",&n,&m);
62     if(m<=2){
63         printf("1\n");
64         return 0;
65     }
66     E.a=E.d=1;
67     F.a=F.b=F.c=1;
68     Ans=Ans+fpm(F,m-1);//先算出纯 fib序列
69
70     for(int i=1;i<=n;++i){//
71         int x;
72         scanf("%d",&x);
73         Ans=Ans+solve(x);
74     }
75     printf("%d\n",Ans.a);
76 }
时间: 2024-07-30 20:30:18

bzoj 3657 斐波那契数列(fib.cpp/pas/c/in/out)的相关文章

用递归和非递归的方法输出斐波那契数列的第n个元素(C语言实现)

费波那契数列(意大利语:Successione di Fibonacci),又译为费波拿契数.斐波那契数列.费氏数列.黄金分割数列. 在数学上,费波那契数列是以递归的方法来定义: {\displaystyle F_{0}=0} {\displaystyle F_{1}=1} {\displaystyle F_{n}=F_{n-1}+F_{n-2}}(n≧2) 用文字来说,就是费波那契数列由0和1开始,之后的费波那契系数就是由之前的两数相加而得出.首几个费波那契系数是: 0, 1, 1, 2, 3

Fibonacci斐波拉契数列----------动态规划DP

n==10 20 30 40 50 46 体验一下,感受一下,运行时间 #include <stdio.h>int fib(int n){ if (n<=1)     return 1; else            return fib(n-1)+fib(n-2); }int main( ){ int n; scanf("%d",&n); printf("%d\n" ,fib(n) );} 先 n==10 20 30 40 50 46

MIT Python 第四课函数抽象与递归简介 最后三分钟递归的经典案例:斐波那契数列

斐波那契数列Fibonacci Sequence,又称黄金分割数列,指的是这样一个数列:0.1.1.2.3.5.8.13.21.……在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*) 有一对一个月大的一公一母的兔子,再过一个月的时候交配生小兔子,假设它们生的是两只一公一母的小兔子,在下一个月末这两只小兔子也有了后代同样是一公一母,问题是一年后你会有多少只小兔子?[呲牙]第三年的时候就像到了澳大利亚... >>&g

【矩阵快速幂】HDU 4549 : M斐波那契数列(矩阵嵌套)

[题目链接]click here~~ [题目大意] M斐波那契数列F[n]是一种整数数列,它的定义如下: F[0] = a F[1] = b F[n] = F[n-1] * F[n-2] ( n > 1 ) 现在给出a, b, n,你能求出F[n]的值吗?对每组测试数据请输出一个整数F[n],由于F[n]可能很大,你只需输出F[n]对1000000007取模后的值即可,每组数据输出一行. [Source] :2013金山西山居创意游戏程序挑战赛――初赛(2) [解题思路] 这个题稍微有点难度,就

青蛙跳台阶问题-斐波拉契数列

题目1:一个台阶总共有n级,如果一次可以跳1级,也可以跳2级.求总共有多少种跳法 首先我们考虑最简单的情况,加入只有1级台阶,那显然只有一种跳法,如果有2级台阶,那就有两种跳的方法了:一种是分两次跳,每次跳1级:另外一种就是一次跳2级 现在我们来讨论一般情况.我们把n级台阶时的跳法看成是n的函数,记为f(n).当n>2时,第一次跳的时候就有两种不同的选择:一是第一次只跳1级,此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1):另外一种选择是第一次跳2级,此时跳法数目等于后面剩下的

斐波拉契数列的计算方法

面试题9.斐波拉契数列 题目: 输入整数n,求斐波拉契数列第n个数. 思路: 一.递归式算法: 利用f(n) = f(n-1) + f(n-2)的特性来进行递归,代码如下: 代码: long long Fib(unsigned int n) { if(n<=0) return 0; if(n==1) return 1; return Fib(n-1) + Fib(n-2); } 缺陷: 当n比较大时递归非常慢,因为递归过程中存在很多重复计算. 二.改进思路: 应该采用非递归算法,保存之前的计算结

斐波那契数列题型ACing

斐波那契数列 特点:头两项均为1,后面任一项都是其前两项之和. 程序在计算中需要用两个变量存储最近产生的两个序列值,且产生了新数据后,两个变量要更新. 问题1:输出斐波那契数列的前十项. int i,x1,x2,x; x1=1; //头两项都是1 x2=1; printf("%6d%6d",x1,x2); for(i=1;i<=8;i++){ //循环输出后8项 x=x1+x2; //计算新项 printf("%6d",x); x1=x2; //更新x1和x2

斐波那契数列算法分析

背景: 假定你有一雄一雌一对刚出生的兔子,它们在长到一个月大小时开始交配,在第二月结束时,雌兔子产下另一对兔子,过了一个月后它们也开始繁殖,如此这般持续下去.每只雌兔在开始繁殖时每月都产下一对兔子,假定没有兔子死亡,在一年后总共会有多少对兔子? 在一月底,最初的一对兔子交配,但是还只有1对兔子:在二月底,雌兔产下一对兔子,共有2对兔子:在三月底,最老的雌兔产下第二对兔子,共有3对兔子:在四月底,最老的雌兔产下第三对兔子,两个月前生的雌兔产下一对兔子,共有5对兔子:……如此这般计算下去,兔子对数分

斐波那契数列的最优算法(O(logN))

相信大家都对斐波那契数列已经相当的熟悉了,最多两分钟就可以写出来以下时间复杂度为O(N)的代码: //递归实现 long long fib(int n) { if (n =1 || n== 2) { return 1; } return (fib(n - 2) + fib(n - 1)); } 或者是这样的时间复杂度为O(N),空间复杂度为O(1): //优化一:时间复杂度为O(N) long long fib(int n) { long long* fibarry = new long lon