输入一个初始位置x_0,范围在1到1,000,000,006
输出小易最少需要使用神秘力量的次数,如果使用次数使用完还没找到贝壳,则输出-1
125000000
1
核心问题
4x+3和8x+7的数学操作,可以用二进制的左移和补1表示
y = 4*x+3,相当于x的二进制左移2位,然后空位补1,即原先x的二进制为#####,则y的二进制为#####11,
y = 8*x+3,相当于y的二进制左移3位,然后空位补1,即原先x的二进制为#####,则y的二进制为#####111
小易的移动,最终可以表达成4x+3操作进行了m次,8x+7操作进行了n次
4*x+3操作进行m次,则x的二进制后面增加2m个1
8*x+7操作进行n次,则x的二进制后面增加了3n个1
小易的移动,最终可以表达为:x的二进制后面增加了(2m+3n)个1
移动的顺序对其到达没有影响
小易移动次数的分析
初始位置为0,则直接满足,需移动0次
初始位置不为0,则记times = (2m+3n),m取1到10_0000,n取1到10_0000
所以,times的取值范围为[2,30_0000]。即:最多30_0000次搜索,就能获得结果。
由于幂次操作数值过大,需要作出变换。参考牛客网用户。
代码如下
import java.util.Scanner;
/**
* Created by Halley on 2017/8/11.
*/
public class Main {
public static final long LIMIT = 300000;//最多搜索次数
public static final long N = 1000000007;//求余
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
System.out.println(sol(sc.nextLong()));
}
}
//次数判定方法
public static long sol(long in){
//如果初始位置为0,则直接可行,返回0次
if(in == 0){
return 0L ;
}else{//初始位置不为0,则开始搜索
return search(in);
}
}
//不为0时的搜索
public static long search(long in){//参数:初始坐标
long temp = in;
//遍历,获取最小位移
for(int i=1;i<=LIMIT;i++){
//long temp = (in+1)*(long)Math.pow(2,i)-1;//当循环较大时,幂次太高,数字超出范围,报错
//递推
temp = (temp * 2 + 1 ) % N;
if( temp % N == 0 ){
//i是符合条件的最小偏移,然后对其进行分解
for(int j =0;j<=(i / 2);j++){//j对应a值
if((i - 2*j) % 3 == 0){
return ((i+j)/3);
}
}
}
}
//超过最大次数还没匹配,则输出-1
return -1L;
}
}
#include <bits/stdc++.h> using namespace std; #define MOD 1000000007LL #define MAX 100000 int main(){ unordered_map<long long,int> vist; for(long long x;cin>>x;vist.clear()){ queue<long long> q; for(long long xx=vist[x]=1,q.push(x);q.size();){ x = q.front(); q.pop(); if (x==0) break; if (vist[x]>MAX) continue; xx=((x<<2)+3)%MOD; if (vist.find(xx)==vist.end()) { q.push(xx); vist[xx]=vist[x]+1; } xx=((x<<3)+7)%MOD; if (vist.find(xx)==vist.end()){ q.push(xx); vist[xx]=vist[x]+1; } } cout<<(q.size()?vist[x]-1:-1)<<endl; } return 0; }
#include <bits/stdc++.h>
#include <tr1/unordered_map>
using namespace std;
using namespace std::tr1;
#define MOD 1000000007LL
#define MAX 100000
#define ITERATOR 10000
int main(){
unordered_map<long long,int> vist;
for(long long i,n=1;1;++n,vist.clear()){
i=rand()%MOD; //伪随机数
queue<long long> q;
long long it=0,xx=1,x;
for(vist[i]=1,q.push(i);q.size();++it){ //迭代次数
x = q.front();
q.pop();
if (x==0) break;
if (vist[x]>MAX) continue;
xx=((x<<2)+3)%MOD;
if (vist.find(xx)==vist.end()) {
q.push(xx);
vist[xx]=vist[x]+1;
}
xx=((x<<3)+7)%MOD;
if (vist.find(xx)==vist.end()){
q.push(xx);
vist[xx]=vist[x]+1;
}
}
//cout<<(q.size()?vist[x]-1:-1)<<endl;
if (it>ITERATOR) cout<<n<<" x="<<i<<", iterate="<<it<<endl;
}
return 0;
}
#include<stdio.h> #include<map> #include<queue> using namespace std; const long long mod=1000000007; struct node{ long long x,step; node(long long x,long long step):x(x),step(step){} }; int main(){ long long x; while(scanf("%lld",&x)!=EOF){ queue<node> Q; map<long long,int> book; Q.push(node(x,0)),book[x]=1; long long res=-1; while(!Q.empty()){ node head=Q.front();Q.pop(); if(head.x%mod==0){ res=head.step; break; } if(head.step>100000) break; long long x1=(4*head.x+3)%mod,x2=(8*head.x+7)%mod; if(book.count(x1)==0){ book[x1]=1; Q.push(node(x1,head.step+1)); } if(book.count(x2)==0){ book[x2]=1; Q.push(node(x2,head.step+1)); } } printf("%lld\n",res); } }//直接bfs就可以啦~
原理也是这个
式子1套式子1
4(4x+3)+3=16(x+1)-1
(x+1)前的数字是这种规律
4,8,16,32....
转换下 2^2,2^3,2^4....
现在我可以列出所有的公式
4(x+1)-1
8(x+1)-1
16(x+1)-1
...
假设32(x+1)-1这个公式中了,其实也就是2^4*(x+1)-1中了。
<thead></thead>2的N次幂 | 超能力使用次数 |
---|---|
2^2 | 1 |
2^3 | 1 |
2^4 | 2 |
2^5 | 2 |
2^6 | 2 |
2^7 | 3 |
。。 | 。。 |
可以发现使用此时是N除3并向上取整
import sys x0=int(sys.stdin.readline().strip()) count=0 s=[] key=-1 fac=2 for i in range(1,3*100000): if (fac*(x0+1)-1)%1000000007==0: key=i break #防止fac过大,所以要取模下 fac=fac*2%1000000007 if key==-1: print(-1) else: print((key-1)//3+1)
import java.util.HashMap;import java.util.LinkedList; import java.util.Map; import java.util.Queue; import java.util.Scanner; public class Main{ public static void main(String[] args) { Scanner in = new Scanner(System.in); while(in.hasNext()){ int x=in.nextInt(); Map<Long, Integer> map=new HashMap<Long, Integer>(); Queue<Long> queue=new LinkedList<Long>(); queue.offer((long)x); map.put((long)x, 1); while(!queue.isEmpty()){ long n=queue.poll(); if(n==0) {System.out.println(map.get(n)-1); return;} if(map.get(n)>=100001) continue; if(!map.containsKey((4*n+3)%1000000007)){ map.put((4*n+3)%1000000007, map.get(n)+1); queue.offer((4*n+3)%1000000007); } if(!map.containsKey((8*n+7)%1000000007)){ map.put((8*n+7)%1000000007, map.get(n)+1); queue.offer((8*n+7)%1000000007); } } System.out.println(-1); } } }
一个简单的方法
#include
using namespace std;
int main(){
long long x0;
long long res=-1;
long long a=1000000007;
cin>>x0;
if(x0%a==0)
return 0;
x0=(x0*4+3)%a;
int i=3;
while(i<=300000){
x0=(x0*2+1)%a;
if(x0==0){
if(i%3==0)
res=i/3;
else
res=i/3+1;
break;
}
i++;
}
cout<<res<<endl;
return 0;
}
#include<iostream> using namespace std; int main() { int rst = -1; long long x0 = 0, n1 = 1, n2 = 1, n0 = 0; cin >> x0; n0 = x0 + 1; n1 = (x0 + 1)*4; n2 = (x0 + 1)*16; for(int k = 0; k<=100000;k++) { if((n0 - 1)%1000000007 == 0) { rst = k; break; } if((n1 - 1)%1000000007 == 0 && k <= 99999) { rst = k + 1; break; } if((n2 - 1)%1000000007 == 0 && k<= 99998) { rst = k + 2; break; } n0 %= 1000000007; n1 %= 1000000007; n2 %= 1000000007; n0 *= 8; n1 *= 8; n2 *= 8; } cout << rst; return 0; }
找规律,迭代时间复杂度太高
#include<stdio.h>
/** 受各位大神指点,用数学公式做**/
int main()
{
int i=0;
long long zs=2, x=0, temp=0;
scanf( "%lld", &x);
for( i=2; i<100000*3; i++)
{
zs=(zs*2)%1000000007;
temp=(zs*(x+1)-1)%1000000007;
if( temp==0)
{
if( i%3==0) printf("%d", i/3);
else printf("%d", i/3+1);
break;
}
}
if( i==100000*3) printf( "-1");
return 0;
}
#include <iostream> using namespace std; const long long STEP = 1000000007; int main(void) { bool flag(1); //这个是为了在循环中强制跳出 long long x, dist, cont; cin >> x; for (int i = 0; i < 3 && flag == 1; i++) //所有f(x)可能性 { dist = x; //没找到重置初始位置信息 cont = 0; //没找到就要重置计数 for (int j = 0; j < i; j++) //先进行f(x)求解,对应0 1 2次 { dist = (4 * dist + 3) % STEP; //结果就是下次的步进数,想不明白可以画个图 cont++; if (dist == 0) { flag = 0; break; } } if (flag == 1) { while (cont <= 100000 && flag == 1) //设置最大次数 { dist = (8 * dist + 7) % STEP; //与f(x)求解方法一样 cont++; if (dist == 0) { flag = 0; break; } } } } if (cont <= 100000) cout << cont << endl; else cout << -1 << endl; return 0; }
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int mod = (int) (1e9+7); int count = -1; int time = 4; for(int i = 1;i <= 300000;i++){ long x = (time * (long)(n) + time -1) % mod; //注意long所在的位置,很关键 //long x=((long )(n)*time+time-1)%mod; if(x == 0){ count = (i+1)/3 + ((i+1)%3 != 0 ? 1:0); /*if((i+1) %3 != 0){ count = (i+1)/3 + 1; } else { count = (i+1)/3; }*/ break; } time = (time*2) % mod; } System.out.println(count); } }
x = int(input()) res, m = 100001, 1000000007 if x%m==0: res = 0 else: ai = (2*(x+1)-1)%m for i in range(2, 300001): ai = (2*ai+1)%m if ai==0: res = i//3+(i%3!=0) break print(res if res<=100000 else -1)
import java.util.Scanner; public class Main { static int mod = 1000000007; static int LIMIT = 100000; public static void main(String[] args) { Scanner in = new Scanner(System.in); long x = in.nextLong(); int cnt = 0; for(int i=0; i<LIMIT; i++){ x %= mod; if(x == 0){ System.out.println(cnt); return; }else{ if(g(g(x)) > mod){ long tmp = x; for(int j=1; j<=2; j++){ tmp = f(tmp); if(tmp % mod == 0){ System.out.println(cnt+j); return; } } } x = g(x); cnt++; } } System.out.println("-1"); } private static Long f(long x){ return 4*x+3; } private static Long g(long x){ return 8*x+7; } }
#include<cstdio> #include<iostream> #include<cstring> #include<map> #include<queue> using namespace std; const long long Mod=1000000007; struct node { long long x; int sum; }; map<long long,int>Map; void bfs(long long sx) { queue<node>Q; node Node; Node.x=sx;Node.sum=0; Q.push(Node); while(!Q.empty()) { if(Map[0]!=0) return; node tmp=Q.front(); Q.pop(); node newNode; newNode.x=(4*tmp.x+3)%Mod; newNode.sum=tmp.sum+1; if(Map[newNode.x]==0) { Map[newNode.x]=newNode.sum; if(newNode.sum>=100000) return; if(newNode.x!=0) Q.push(newNode); } newNode.x=(8*tmp.x+7)%Mod; newNode.sum=tmp.sum+1; if(Map[newNode.x]==0) { Map[newNode.x]=newNode.sum; if(newNode.sum>=100000) return; if(newNode.x!=0) Q.push(newNode); } } return ; } int main() { long long n; cin>>n; if(n%Mod==0) { cout<<"0"<<endl; return 0; } bfs(n); if(Map[0]==0) cout<<"-1"<<endl; else cout<<Map[0]<<endl; return 0; }
#include <iostream>#include<bits/stdc++.h>#include<queue>#include <map>#define mod 1000000007LLusing namespace std;//int vis[200000000]={0};int main(){map<long long,int> vis;queue<long long >q;int n;long long xx;while(cin>>n){int count=0;int ok=0;vis.clear();q.push(n);vis[n]=1;while(!q.empty()){long long a=q.front();q.pop();if(a==0){ok=1;count=vis[a];break;}if(vis[a]>100000) continue;xx=(4*a+3)%mod;if(!vis[xx]){q.push(xx);vis[xx]=vis[a]+1;}xx=(8*a+7)%mod;if(!vis[xx]){q.push(xx);vis[xx]=vis[a]+1;}}if(ok)cout<<count-1<<endl;else cout<<-1<<endl;}return 0;}
速度不快但是思路简单。
4x + 3等于做了两次2x + 1, 8x + 7做了三次。
从起点开始令x0 = 2*x0 + 1,统计做了多少次2x + 1后模1000000007等于0
#include <stdio.h> #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; }
x=x+1; x=(x*2)%1000000007; x=(x*2)%1000000007; x=(x+1000000006)%1000000007;
#include<cstdio> int x87(int x, int x43){ if(x==1000000006)return 100005; //永远都差1步吃到草的 int count=0; while(x43>0 && x%1000000007!=0){ x++; x=(x*2)%1000000007; x=(x*2)%1000000007; x=(x+1000000006)%1000000007; count++; x43--; } while(x%1000000007!=0){ x++; x=(x*2)%1000000007; x=(x*2)%1000000007; x=(x*2)%1000000007; x=(x+1000000006)%1000000007; count++; if(count>100000)return 100005; //次数用完,吃不到 } return count; } int main(){ int x,f1=0,f2=0,f3=0,res=0; scanf("%d",&x); f1=x87(x,0); f2=x87(x,1); f3=x87(x,2); if(f1<f2)res=f1; else res=f2; if(f3<res)res=f3; if(res>100004)printf("-1\n"); else printf("%d\n",res); return 0; }