HDOJ 4518題目連結
1,把合格fibonacci數按反向建立AC自動機的樹,最後一個節點標記flag = 1,表明該節點fibonacci數的尾節點;
2,對於i位的所有數字,狀態在當前節點中的個數存起來num【i】
3,在加入另外一個fibonacci1數字時,如果之前已經有fibonacci數是該數位首碼時,可以不用加入該fibonacci1了;
建立資料結構
struct Node
{
Node *son[10];
Node *fail;
bool flag;
LL num[13];
}
4,求出每個節點的失敗節點(注意失敗節點要用廣度優先搜尋),如果失敗節點是一個fibonacci數的尾節點,那麼該節點中也包含了fibonacci數,該節點flag也可以設定成flag = 1;
5,如果在某個flag = 1的節點狀態中加入數字,那麼不管加入的數字是什麼(0,1……9),下一個狀態中一定含有fibonacci數,所以只要讓num【i+1】+= num[i] * 10;
6,求第x個最終數y時,從y的最高位(0……9)開始遍曆i,當能找到的最終數大於或者等於x時,那麼該位就是i,通過遞迴,計算出所有的位
7,對於x位的數字,不用擔心前置0的情況,因為不存在前置0的fibonacci數,並且前置0還可以方便加入更高位時的方便
My Code:(調試了好久終於出來了)
#include<stdio.h>
#include<string.h>
typedef __int64 LL;
#define MAX ((LL)200000000000)
LL fibonacci[201], fnum;
LL final[201], finum;
struct Node
{
Node *son[10];
Node *fail;
bool flag;
LL num[13];
}root;
LL result[201], rnum;
LL abs(LL a)
{
return a > 0 ? a : -a;
}
LL Min(LL a, LL b)
{
return a < b ? a : b;
}
int initNode(Node *p)
{
int i;
for(i = 0; i <= 9; i ++)
{
p -> son[i] = NULL;
}
p -> fail = NULL;
p -> flag = 0;
memset(p -> num, 0, sizeof(p -> num));
return 0;
}
int build(LL x)
{
Node *p = &root;
while(x > 0)
{
if(p -> flag)
return 0;
if(p -> son[x % 10] == NULL)
{
p -> son[x % 10] = new Node;
initNode(p -> son[x % 10]);
}
p = p -> son[x % 10];
x /= 10;
}
p -> flag = 1;
return 0;
}
int get(int step, Node *p)
{
int i;
Node *temp;
if(p -> flag)
{
p -> num[step] += p -> num[step - 1] * 10;
return 0;
}
for(i = 0; i <= 9; i ++)
{
if(p -> son[i] != NULL)
{
p -> son[i] -> num[step] += p -> num[step - 1];
get(step, p -> son[i]);
}
else
{
temp = p-> fail;
while(1)
{
if(temp -> son[i] != NULL)
{
temp -> son[i] -> num[step] += p -> num[step - 1];
break;
}
if(temp == &root)
{
root.num[step] += p -> num[step - 1];
break;
}
temp = temp -> fail;
}
}
}
return 0;
}
int getFail()
{
int i;
Node *temp;
Node *que[300];
int qnum = 0;
root.fail = &root;
for(i = 0; i <= 9; i ++)
{
if(root.son[i] != NULL)
root.son[i] -> fail = &root;
}
for(i = 0; i <= 9; i ++)
{
if(root.son[i] != NULL)
que[++ qnum] = root.son[i];
}
int front = 1;
while(front <= qnum)
{
if(que[front] -> fail -> flag == 1)
que[front] -> flag = 1;
for(i = 0; i <= 9; i ++)
{
if(que[front] -> son[i] == NULL)
continue;
temp = que[front] -> fail;
while(temp -> son[i] == NULL && temp != &root)
{
temp = temp -> fail;
}
if(temp -> son[i] != NULL)
que[front] -> son[i] -> fail = temp -> son[i];
else
que[front] -> son[i] -> fail = &root;
que[++ qnum] = que[front] -> son[i];
}
front ++;
}
return 0;
}
LL insert(LL temp, int pre, Node *p)
{
int i;
LL result = 0;
// if(p == root.son[3])
// printf("!");
Node *q = p;
LL temp1 = temp;
if(p -> flag)
{
result += p -> num[pre];
}
else
while(temp1 > 0)
{
while(q -> son[temp1 % 10] == NULL)
{
if(q -> fail == q)
break;
q = q -> fail;
}
if(q -> son[temp1 % 10] == NULL)
break;
q = q -> son[temp1 % 10];
if(q -> flag == 1)
{
result += p -> num[pre];
break;
}
temp1 /= 10;
}
for(i = 0; i <= 9; i ++)
{
if(p -> son[i] != NULL)
{
result += insert(temp, pre, p -> son[i]);
}
}
return result;
}
LL getResult(LL temp, int pre, LL x)
{
int i;
if(pre == 0)
return temp;
LL getnum = 0;
LL lastnum = 0;
for(i = 0; i <= 9; i ++)
{
temp *= 10;
temp += i;
getnum += insert(temp, pre - 1, &root);
if(getnum >= x)
{
return getResult(temp / 10 * 10 + i, pre - 1, x - lastnum);
}
temp /= 10;
lastnum = getnum;
}
return 0;
}
int init()
{
int i;
fibonacci[1] = fibonacci[2] = 1;
fnum = 2;
while(1)
{
fnum ++;
fibonacci[fnum] = fibonacci[fnum - 2] + fibonacci[fnum - 1];
if(fibonacci[fnum] > MAX)
break;
}
initNode(&root);
for(i = 1; i <= fnum; i ++)
{
if(fibonacci[i] > 10)
build(fibonacci[i]);
}
getFail();
root.num[0] = 1;
for(i = 1; i <= 12; i ++)
{
get(i, &root);
}
rnum = 1;
while(1)
{
++ rnum;
result[rnum] = getResult(0, 12, fibonacci[rnum]);
if(result[rnum] > MAX)
break;
}
return 0;
}
int main()
{
int i;
init();
// for(i = 2; i <= rnum ; i ++)
// printf("%I64d ", result[i]);
// printf("\n");
LL n;
LL min;
while(scanf("%I64d", &n) != EOF && n != -1)
{
min = MAX;
for(i = 2; i <= rnum; i ++)
{
min = Min(min, abs(n - result[i]));
}
printf("%I64d\n", min);
}
return 0;
}