题意:
一只青蛙想从0点到200点,在1-199上每点存在荷叶,荷叶上可以放置传送门,从某点立即瞬移到另一个点,一个点只有一个传送门。青蛙每次可以跳一步或者两步。
问从0到200存在m个方案数的传送门放置方法。
(一)找规律
思路:只用加法和乘法两种运算符,尽可能地将M用斐波那契数表示出来。
这里只用了M-1
和M/f[i]
两种操作(f[i]
代表斐波那契数)。
先将斐波那契打个表,用long long
打到50就够用了。
先判断M能否被斐波那契数整除(从大到小判断,斐波那契数最小到2,因为1没什么用,会陷入死循环)。
可以整除的话就做M/f[i]
操作,不能整除的话就做M-1
的操作。#include<bits/stdc++.h> typedef long long int ll; using namespace std; typedef pair<int,int> P; const int maxn = 100; ll f[maxn]; void init() { f[0]=1,f[1]=1; for(int i=2; i<=50; i++) f[i]=f[i-1]+f[i-2]; } vector<P> ans; int main() { //FRER() //FREW() ll n; init(); while(scanf("%lld",&n)!=EOF) { ans.clear(); // 特判一下1和2 if(n==1) { printf("2\n1 199\n2 2\n"); continue;} else if(n==0) { printf("2\n1 1\n2 1\n"); continue;} //定义一个临时变量t,代替n进行后续操作 ll t=n; int now_pos=0;//表示现在的位置 while(1) { if(t==1) break; int is=0;//判断是否能整除斐波那契数,可以为1,不可为0 //寻找能被t整除的斐波那契数 for(int j=50; j>=2; j--) { if((t>=f[j])&&(t%f[j])==0) { //可以整除,看图示 D-1 now_pos+=j; ans.push_back(make_pair(now_pos+1,now_pos+1)); now_pos+=2; t/=f[j]; is=1; break; } } if(is) continue; //不能整除,-1操作,看图示 D-2 ans.push_back(make_pair(now_pos+1,199)); now_pos+=2; t-=1; } ans.push_back(make_pair(now_pos,199)); printf("%d\n",ans.size()); for(int i=0; i<ans.size(); i++) { printf("%d %d\n",ans[i].first,ans[i].second); } } return 0; }
(二)二进制拆分
对M进行二进制拆分。例如5=(101)2,相当于5=1+0+4;11=(1011)2,相当于11=1+2+0+8。
也就是说只需要加法
和乘2
两种操作。
二进制位为1
的时候,进行乘2
,为0
的时候进行加法
操作。#include <stdio.h> #define ll long long int main() { ll n; while(~scanf("%lld",&n)) { printf("66\n198 198\n197 197\n"); for(ll i = 0; i < 32; ++i) { printf("%lld %lld\n",6*i+5,6*i+5); if(n&(1<<i)) printf("%lld %lld\n",6*i+1,199); else printf("%lld %lld\n",6*i+1, 6*i+1); } } return 0; }