2017校招真题在线编程-饥饿的小易

题目描述

小易总是感觉饥饿,所以作为章鱼的小易经常出去寻找贝壳吃。最开始小易在一个初始位置x_0。对于小易所处的当前位置x,他只能通过神秘的力量移动到 4 * x + 3或者8 * x + 7。因为使用神秘力量要耗费太多体力,所以它只能使用神秘力量最多100,000次。贝壳总生长在能被1,000,000,007整除的位置(比如:位置0,位置1,000,000,007,位置2,000,000,014等)。小易需要你帮忙计算最少需要使用多少次神秘力量就能吃到贝壳。

输入描述:

输入一个初始位置x_0,范围在1到1,000,000,006

输出描述:

输出小易最少需要使用神秘力量的次数,如果使用次数使用完还没找到贝壳,则输出-1
示例1

输入

125000000

输出

1


思路:这道题目需要用到一个确实成立的猜想:(ax+b)%c = a(x%c)+b 这样我们就能够只使用余数来对整个数的变化情况进行跟踪。
   通过一个队列queue来保存每一步变化可能出现的新的余数值,一个unordered_set来保存已经出现过的余数值。因为已经出现过的余数值再次出现就没有任何意义了,所以不用再次加入到变化队列里面。
   总的来说还是一个广度优先搜索的思路,不过剪枝得应该比较厉害,总体运行时间能够通过。
//运行时间122ms
#include<iostream> #include<unordered_set> #include<queue> using namespace std; int main(){ long long init; cin>>init; queue<long long> q; unordered_set<long long> s; q.push(init); s.insert(init); int res = 0; long long temp ; while(!q.empty() && res <=100000){ int size = q.size(); for(int i = 0; i<size; ++i){ temp = q.front(); q.pop(); if(temp == 0) { cout<<res; return 0; } int t = (temp*4 + 3)%1000000007; if(! s.count(t)) { q.push(t); s.insert(t); } t = (temp*8 + 7)%1000000007; if(! s.count(t)) { q.push(t); s.insert(t); } } ++res; } if(res == 100001 || q.empty()) cout<<-1; else cout<<res; return 0; }

从网上其他答案中找到一些比较巧妙的在这里贴一下,有些比较需要数学技巧:

 

观察变换形式,并做变形:

4x+3=4(x+1)-1

8x+7=8(x+1)-1

如果多层嵌套呢?

y=4x+3

8y+7=8((4(x+1)-1)+1)-1=8(4(x+1))-1=32(x+1)-1

如果你多枚举一些,就会发现,能变换出的数的形式都是:

a(x+1)-1,其中a是2的>=2的幂次数(4、8、16、32、64、……)

我们能否利用这个特点呢?

 

当然能!

考虑直接枚举那个a,从2^2一直到……等等,最大是2的多少次?

答:直接考虑最大情况,每次变换都选择8x+7那种,也就是,每次a乘上8,也就是说,最坏是(2^3)^100000=2^300000次

所以,枚举a,从2^2次,一直到2^300000次

然后,对每个a检查一下,乘起来结果%1e9+7是不是0,如果是0,说明100000次之内有解

——问:那最小要执行几次变换?

答:我们直接贪心,尽量让a乘8(乘2次8和乘3次4一样大,当然是乘8越多,变换次数越少)

——问:如果我发现a==2^5或a==2^4的时候满足要求,但是5和4才不能表示成3的倍数,怎么办?

答:别忘了你手上还有4x+3的变换(就是a乘4的变换)

对5这种情况,除以3余2,那刚好,用一次乘4的变换就行了

对4这种情况,除以3余1,我们考虑,消去一个乘8的变换,用2个乘4的变换代替并补足。

 

计算上,直接/3作为结果,如果有余数,就要结果再加1次

#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <math.h>
#include <algorithm>
#include <map> 
#include <queue>
using namespace std;
typedef long long ll;
 
const int mod=1e9+7;
 
int main(){
    int n;
    while(~scanf("%d",&n)){
        int times=4;
        int ans=100001;
        for(int i=1;i<=300000;++i){
            int x=((long long)(n)*times+times-1)%mod;
            if(x==0){
                ans=(i+1)/3+((i+1)%3?1:0);
                break;
            }
            times=times*2%mod;
        }
        printf("%d\n",ans>100000?-1:ans);
    }
    return 0;
}

 

posted @ 2018-08-09 10:08  J1ac  阅读(325)  评论(0编辑  收藏  举报