数据结构 绪论 不一样的 fibonacci 数列

★实验任务 Winder最近在学习fibonacci
数列的相关知识。我们都知道fibonacci数列的递推公式是F(n)=F(n-1)+F(n-2)(n>=2 且n 为整数)。
Winder想知道的是当我们将这个递推式改为F(n)=AF(n-1)+BF(n-2)(n>=2且n为整数)时我们得到的是怎样的数列。但是,Winder很懒,所以只能由你来帮他来完成这件事。
注意,这里我们依然令F(0)=F(1)=1。
★数据输入 输入第一行三个正整数N,A 和B(N<=10;1<=A、B<=100
且均为整数)。 接下来有N 行,每行一个自然数n(n<=100000000)。 ★数据输出
输出一行一个整数F(n),由于结果可能会很大,Winder要求输出结果对2013取模。

分析:
初看这题 1e8的数据 估计暴力不能解决,然而还是暴力了,结果全部TLE
考虑到fib数组可能会有重复性,因为是对2013取模,而fib[i] 取决于 fib[i-1] 和 fib[i-2]
显然如果两个数连续相同 就会有循环
什么意思呢

例如 1 2 3 4 1 2
这里 1 2 和 后面 1 2 是一样的
可以推出整个序列就是 1 2 3 4 1 2 3 4 ……
所以只要知道循环的起点和循环结就可以了
这个时候的数据量最大为4e6
由于利用set进行插入和判重
因此时间复杂度为O(nlogn)

set的判重根据的是 < 运算符的重载。

这个时间复杂度对于 4e6的数据量来说是可行的。
算法如下

#include<bits/stdc++.h>
#define LL long long
#define ms(s) memset(s, 0, sizeof(s))
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define INF 0X7fffffff
using namespace std;
const int maxn = 5e6 + 10;
const int MOD = 2013;
LL fib[maxn];
struct node {
    int a, b;
    int pos;
    node(int a, int b, int pos): a(a), b(b), pos(pos){}
    node(){}
    friend bool operator < (const node& n1, const node& n2) {
        return n1.a != n2.a || n1.b != n2.b;
    }
};

set<node> ss;


/*
F(n)=AF(n-1)+BF(n-2)(n>=2且n为整数) F(0)= F(1)=1。
n <= 100000000 MOD 2013
*/

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    ios::sync_with_stdio(false);
    cin.tie(0);
    LL a, b, t;
    cin >> t >> a >> b;
    fib[0] = fib[1] = 1;
    ss.insert(node(1, 1, 1));
    int circle;
    int first;
    for(int i = 2; i <= maxn; i++) {
        fib[i] = (a * fib[i - 1] + b * fib[i - 2]) % MOD;
        //cout << fib[i] << " " << fib[i - 1] << endl;
        node n(fib[i - 1], fib[i], i);
        if(ss.count(n)) {
            // cout << fib[i - 1] << " " << fib[i] << endl;
            // cout << ss.find(n) -> a << " " << ss.find(n) -> b << endl;
            first = ss.find(n) -> pos;
            circle = i - ss.find(n) -> pos;
            //cout << first << " " << circle << endl;
            break;
        }
        ss.insert(n);
    }
    while(t--) {
        cin >> a;
        if(a <= first) cout << fib[a] << endl;
        else {
            a = (a - first) % circle + first;
            cout << fib[a] << endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值