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还可以方便加入更高位时的方便
我的代码:(调试了好久终于出来了)
#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;
}