百度之星2012年冬季邀请赛第一题分析

来源:互联网 发布:网络销售公司介绍 编辑:程序博客网 时间:2024/04/30 07:34

问题描述

[描述]

    du熊对数学一直都非常感兴趣。最近在学习斐波那契数列的它,向你展示了一个数字串,它称之为“斐波那契”串:

        11235813471123581347112358........

    聪明的你当然一眼就看出了这个串是这么构造的:

        1.先写下两位在0~9范围内的数字a, b,构成串ab;
        2.取串最后的两位数字相加,将和写在串的最后面。

    上面du熊向你展示的串就是取a = b = 1构造出来的串。
    显然,步骤1之后不停地进行步骤2,数字串可以无限扩展。现在,du熊希望知道串的第n位是什么数字。

[输入]
    输入数据的第一行为一个整数T(1 <= T <= 1000), 表示有T组测试数据;
    每组测试数据为三个正整数a, b, n(0 <= a, b < 10, 0 < n <= 10^9)。

[限制]
    Time Limit: 2000/1000ms (C/Other) 
    Memory Limit: 65535/32768K (C/Other)

[来源]
    http://astar.baidu.com/index.php?r=home/detail&id=2


要点

(1)每次需要构造的时候,只依赖于末尾的两个数有关,而和前面的其他数字无关。
(2)因为只依赖于末尾的两个数字,所有最多可能的状态数为10*10=100,因此如果不断循环下去必然存在循环节
(3)编码细节需要多加以注意

实现 

#include <stdio.h>#include <vector>#include <string>#include <assert.h>using std::vector;using std::string;struct next_t{unsigned intnextu;unsigned intnextv;unsigned intcarry;public:next_t(unsigned int u = 0,unsigned int v = 0,unsigned int c = 0):nextu(u),nextv(v),carry(c) { ; }};struct chain_t{stringprefix;stringcycle;};int main(){static const unsigned int digit_set_size = 10;next_t nexts[digit_set_size][digit_set_size];// 状态迁移表for(unsigned int i = 0;i < digit_set_size;++i){for(unsigned int k = 0;k < digit_set_size;++k){unsigned int x = i + k,u = 0,v = 0,c = 0;if(x < digit_set_size) u = k,v = x,c = 0;else u = x/digit_set_size,v = x%digit_set_size,c = 1;nexts[i][k] = next_t(u,v,c);}}chain_t chains[digit_set_size][digit_set_size];for(unsigned int i = 0;i < digit_set_size;++i){for(unsigned int k = 0;k < digit_set_size;++k)// 计算每种状态的状态链,直到循环节出现{size_t serial[digit_set_size][digit_set_size] = { 0 };// 每种状态在trace中的位置memset(serial,0xff,sizeof(serial));string trace;trace.push_back('0'+i);// trace.push_back('0'+k);unsigned int p = i,q = k,z = 0;for(;serial[p][q] == (size_t)(-1);++z)// 注意一种情况:257 1235813471 12{assert(trace.size() >= 2);serial[p][q] = trace.size() - 2;next_t r = nexts[p][q];p = r.nextu;q = r.nextv;if(0 != r.carry) trace.push_back('0'+p);trace.push_back('0'+q);}assert(serial[p][q] + 2 < trace.size());size_t prefix_len = serial[p][q];chains[i][k].prefix = trace.substr(0,prefix_len);chains[i][k].cycle = trace.substr(prefix_len,trace.size()-prefix_len-2);// 注意:最末尾的2位其实是已经重复的状态,这两位有可能都是最后添加的,也有可能有一位是前一次添加的//printf("(%u,%u) %s,%s\n",i,k,chains[i][k].prefix.c_str(),chains[i][k].cycle.c_str());}}unsigned int nCases = 0;scanf("%d",&nCases);for(unsigned int iCases = 1;iCases <= nCases;++iCases){unsigned int a = 0,b = 0,n = 0;scanf("%d%d%d",&a,&b,&n);const chain_t& r = chains[a][b];unsigned int loopdis = (unsigned int)(r.prefix.size());unsigned int loopsize = (unsigned int)(r.cycle.size());unsigned int ans = 0;if(n <= loopdis) ans = (unsigned int)(r.prefix[n-1] - '0');// 注意等号else{unsigned int pos = (n - loopdis)%loopsize;if(0 == pos) pos = loopsize;// 注意整除的情况ans = (unsigned int)(r.cycle[pos-1] - '0');}printf("Case #%u: %u\n",iCases,ans);}return 0;}