★实验任务 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;
}