链接:
大致题目意思:
Ntarsis收到了两个整数n和k作为他的生日礼物。他想知道有多少个长度为k的斐波那契类似序列可以使n成为序列的第k个元素。
如果对于所有i>2,fi=fi−1+fi−2,其中fi表示序列中的第i个元素,则称非递减非负整数序列为斐波那契类似序列。注意f1和f2可以是任意的。
例如,序列[4,5,9,14]和[0,1,1]被认为是斐波那契类似序列,而[0,0,0,1,1],[1,2,1,3]和[-1,-1,-2]不是:前两个序列不总满足fi=fi−1+fi−2,最后一个序列不满足元素非负。
帮助Ntarsis完成这个任务,给他留下深刻的印象。
输入:
第一行包含一个整数t(1≤t≤2⋅105),表示测试用例的数量。每个测试用例的描述如下。
每个测试用例包含两个整数n和k(1≤n≤2⋅105,3≤k≤109)。
保证所有测试用例中的n的总和不超过2⋅105。
输出:
对于每个测试用例,输出一个整数,表示长度为k且第k个元素为n的斐波那契类似序列的数量。即输出长度为k且满足fk=n的序列f的数量。可以证明这个数量是有限的。
思路:
我们先处理出最后面的两个数,第k个元素为n,第k-1个元素从n/2开始一直循环到等于n(因为n等于前面两个数的和,而前一个元素小于等于后面一个元素,所以第k-1个元素从n/2开始循环)。
然后深搜前面的每一位元素,定义当前元素左端点为0,右端点为后面一个元素的值,然后二分查找能否当前值加上后面一个元素的值等于后面第二个元素的值,一旦找不到,返回0(无法构成斐波拉契序列),一直深搜到第0位元素的时候,直接返回1(找到斐波拉契序列)。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,cnt;
int dfs(int v,int one,int tow){
if(v==0) return 1;
int l=0,r=one;
while(l<r){
int mid=(l+r)/2;
if(mid+one<tow) l=mid+1;
if(mid+one>tow) r=mid-1;
if(mid+one==tow) {l=mid;break;}
}
if(l+one==tow){
if(dfs(v-1,l,one)) return 1;
else return 0;
}
else return 0;
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);
int t;
cin>>t;
while(t--){
cnt=0;
cin>>n>>k;
for(int i=(n+1)/2;i<=n;i++)
cnt+=dfs(k-2,i,n);
cout<<cnt<<"\n";
}
}