链接:https://www.nowcoder.com/acm/contest/71/C
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
小W在计算一个数列 An A n ,其中 A1=1,A2=2,An+2=An+1+An A 1 = 1 , A 2 = 2 , A n + 2 = A n + 1 + A n 。尽管他计算非常精准,但很快他就弄混了自己的草稿纸,他找出了一些他计算的结果,但他忘记了这些都是数列中的第几项。
输入描述:
每行包括数列中的一项 Ak(k<=100000) A k ( k <= 100000 ) 。
总行数 T<=30 T <= 30 。
输出描述:
对于每一项 Ak A k ,输出一行包括一个正整数 k k 表示输入中数是数列的第几项。
示例1
2
3
5
8
13
输出
2
3
4
5
6
分析
本题题意很简单,问题在于,给定的值过大,这个数列早就已经超过了 long long 的范围,因此我们采用 hash 的思想,给数列中的每一项做一个 id i d 映射到对应的下标。对于本题,我们可以选择若干个大质数(例如5个),质数选的越大越多就越不容易发生hash 冲突,求取 Ai(i≤100000) A i ( i ≤ 100000 ) 对5个大质数取模后的结果,然后对于每次询问,我们同样去模这些大质数,最后判断每个查询对应的质数取模数组和之前算过的某个是否完全相同,如果完全相同,则返回该下标即可。代码1是这样实现的。对于本题来说将 Ai(i≤100000) A i ( i ≤ 100000 ) 的值记为 Ai(i≤100000) A i ( i ≤ 100000 ) 的真实值对 long long 自然溢出的结果,也是可行的,可能是数据比较水吧。代码2是这样实现的。
//代码1
#include <bits/stdc++.h>
#define N int(1e5+5)
using namespace std;
typedef unsigned long long ll;
ll arr[N][6];
ll mod[5]={1000000007,1000000009,91815541,68861641,51646229};
ll t[5];
int main(void)
{
for(int i = 0;i < 5;i ++){
arr[1][i] = 1;
arr[2][i] = 2;
}
for(int i = 3;i <= int(1e5);i ++){
for(int j = 0;j < 5;j ++)
arr[i][j] = (arr[i - 1][j] + arr[i - 2][j]) % mod[j];
}
string s;
while(cin >> s){
memset(t,0,sizeof(t));
for(int i = 0;i < s.size();i ++)
for(int j = 0;j < 5;j ++)
t[j] = (t[j] * 10 + s[i] - '0') % mod[j];
for(int i = 1;i <= int(1e5);i ++){
bool ok = 1;
for(int j = 0;j < 5;j ++){
if(arr[i][j] != t[j]){
ok = 0;
break;
}
}
if(ok){
cout << i << endl;
break;
}
}
}
return 0;
}
//代码2
#include <bits/stdc++.h>
#define N int(1e5+5)
using namespace std;
long long arr[N];
int main(void)
{
arr[1] = 1;
arr[2] = 2;
for(int i = 3;i <= 1e5;i ++){
arr[i] = arr[i - 1] + arr[i - 2];
}
string t;
while(cin >> t){
long long num = 0;
for(int i = 0;i < t.size();i ++)
num = num * 10 + t[i] - '0';
for(int i = 1;i <= 1e5;i ++){
if(arr[i] == num){
cout << i << endl;
break;
}
}
}
return 0;
}