大体题意:
告诉你一个长度不超过40的字符串,要求找出最小的斐波那契数列的位置 使得这个字符串是那个斐波那契数的前缀!
如果100000项以内的斐波那契数列没有它,输出-1!
思路:
思路很明显:
直接先预处理出来1~100000以内的斐波那契数列来, 只用到了高精度加法,拿字符串模拟即可!
然后求出一项来,插入到字典树中,字典树每一个节点的权值代表着以他为终点的前缀 是 斐波那契数的哪一项!不断取最小值即可!
仅供参考吧, 代码很慢! 5400多ms 才过的!
想了想 慢就慢在算高精度加法上了!
详细见代码:
=============================================
重新更新一下这篇博客!
这个题目也是HDU 4099 的题目,我的时间是5400ms 显然过不了 HDU 的5s限制! 能过也是爆内存!
有一个优化 它算的只是前40位, 数据范围是10W项, 它的位数也差不多10w位左右! 我们只保存 前50位即可!超出的部分割掉即可! 这样无论在速度还是内存上都优化了不少!
详细见代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define min(x,y) (x) > (y) ? (y) : (x)
#define max(x,y) (x) > (y) ? (x) : (y)
using namespace std;
const int maxn = 50 + 7;
const int inf = 0x3f3f3f3f;
char q[41];
char s1[maxn], s2[maxn], s3[maxn], tmp[maxn];
struct Tree{
int v;
Tree* next[10];
Tree(int v = inf):v(v){ for (int i = 0; i < 10; ++i) next[i] = NULL; }
}*root;
void insert(char* s,int k) {
Tree* cur = root;
for (int i = 0; s[i] && i < 41; ++i){
int id = s[i] - 48;
if (cur -> next[id] == NULL){
cur -> next[id] = new Tree();
}
cur = cur -> next[id];
cur->v = min(cur->v,k);
}
}
int query(char* s) {
Tree* cur = root;
for (int i = 0; s[i]; ++i){
int id = s[i] - 48;
if (cur->next[id] == NULL)return -1;
cur = cur->next[id];
}
return cur->v;
}
void init(){
root = new Tree();
s1[0] = s2[0] = '1';
s1[1] = s2[1] = 0;
insert(s1,0);
insert(s2,1);
for (int k = 2; k < 100000; ++k){
int len1 = strlen(s1);
int len2 = strlen(s2);
if (len2 > 50){
s2[--len2] = 0;
s1[--len1] = 0;
}
int flag = 0, i, j;
i = len1-1,j = len2-1;
int p = max(i,j);
s3[p+1]=0;
while(i >= 0 || j >= 0){
int t = flag;
if (~i) t += s1[i] - 48;
if (~j) t += s2[j] - 48;
s3[p] = t%10+48;
if (t > 9) flag = 1;
else flag = 0;
if (~i)--i;
if (~j)--j;
--p;
}
int ps = 0;
if (flag){
tmp[ps++] = flag + 48;
}
tmp[ps] = 0;
strcat(tmp,s3);
insert(tmp,k);
strcpy(s1,s2); strcpy(s2,tmp);
}
}
void Free(Tree* ro){
if (ro == NULL) return;
for (int i = 0; i < 10; ++i){
if (ro->next[i] != NULL) Free(ro->next[i]);
}
// ro = NULL;
free(ro);
}
int main(){
init();
int T,ks=0;
scanf("%d",&T);
while(T--){
int n;
scanf("%s",&q);
printf("Case #%d: %d\n",++ks,query(q));
}
Free(root);
return 0;
}
===============================
以下为 5400ms 代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define min(x,y) (x) > (y) ? (y) : (x)
#define max(x,y) (x) > (y) ? (x) : (y)
using namespace std;
const int maxn = 100000 + 7;
const int inf = 0x3f3f3f3f;
char q[45];
char s1[maxn], s2[maxn], s3[maxn], tmp[maxn];
struct Tree{
int v;
Tree* next[10];
Tree(int v = inf):v(v){ for (int i = 0; i < 10; ++i) next[i] = NULL; }
}*root;
void insert(char* s,int k) {
Tree* cur = root;
int cnt = 0;
for (int i = 0; s[i] && cnt < 50; ++cnt,++i){
int id = s[i] - 48;
if (cur -> next[id] == NULL){
cur -> next[id] = new Tree();
}
cur = cur -> next[id];
cur->v = min(cur->v,k);
}
}
int query(char* s) {
Tree* cur = root;
for (int i = 0; s[i]; ++i){
int id = s[i] - 48;
if (cur->next[id] == NULL)return -1;
cur = cur->next[id];
}
return cur->v;
}
void init(){
root = new Tree();
s1[0] = s2[0] = '1';
s1[1] = s2[1] = 0;
insert(s1,0);
insert(s2,1);
for (int k = 2; k < 100000; ++k){
int len1 = strlen(s1);
int len2 = strlen(s2);
int flag = 0;
int i,j;
i = len1-1,j = len2-1;
int p = max(i,j);
s3[p+1]=0;
int way = (k & 1) ? 1 : 0;
while(i >= 0 || j >= 0){
int t = flag;
if (~i) t += s1[i] - 48;
if (~j) t += s2[j] - 48;
s3[p] = t%10+48;
if (t > 9) flag = 1;
else flag = 0;
if (~i)--i;
if (~j)--j;
--p;
}
int ps = 0;
if (flag){
if (way) s2[ps++] = flag + 48;
else s1[ps++] = flag+48;
}
if (way){
s2[ps] = 0;
strcat(s2,s3);
insert(s2,k);
}
else {
s1[ps] = 0;
strcat(s1,s3);
insert(s1,k);
}
}
}
int main(){
init();
int T,ks=0;
scanf("%d",&T);
while(T--){
int n;
scanf("%s",&q);
printf("Case #%d: %d\n",++ks,query(q));
}
return 0;
}