Evanyou Blog 彩带

李总不知从哪里找的鬼题——无限序列

先上题目:

1、无限序列
infinit.pas/c/cpp
1s / 128M
[问题描述]
我们按以下方式产生序列:
1、 开始时序列是: "1" ;
2、 每一次变化把序列中的 "1" 变成 "10" ,"0" 变成 "1"。
经过无限次变化,我们得到序列"1011010110110101101..."。
总共有 Q 个询问,每次询问为:在区间 A 和 B 之间有多少个 1。
请写一个程序回答 Q 个询问。
[输入数据]
第一行为一个整数 Q,后面有 Q 行,每行两个数用空格隔开的整数 a, b。
[输出数据]
共 Q 行,每行一个回答
[输入样例]
1
2 8
[输出样例]
4
[数据范围]
1 <= Q <= 5000
1 <= a <= b < 2^63

------------------------------------------------------------------分割线-----------------------------------------------------------------------

本来一开始一位是要根据数列规律来计算,于是找规律找循环找了半天,最后看了解析才TM地发现居然是斐波那契。。。。。。好吧,先看看下面这几组序列:

1

10

101

10110

10110101

1011010110110

101101011011010110101

......

看了这几个序列是不是发现了什么?对,第i个序列就是在第i-1个序列后面接上第i-2个序列,所以。。。。。。斐波那契。。。。。。

不过要想实现还是需要点思维,必须找到一个斐波那契数f[n],使得a<=f[n-1]<b<f[n],然后将a,b分为两段,直到每一段的长度都是斐波那契数为止(因为只有这样才能求出第a到第b个数之间的1的个数)

具体还是看下代码吧(其实就是我懒):

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll n;
ll a,b,f[93],ff[93];
/*切记,斐波那契数到第92个就会爆long long
而这一题的范围正好是long long以内,所以就开到92*/ ll find(ll num,ll x,ll y) {
if(x==0||y==0) return 0; if(num==1) return 1; if(num==2) return x==2?0:1; if(x==1&&y==f[num]) return ff[num]; ll cnt=0; if(x<=f[num-1]) { if(y>f[num-1]) cnt=cnt+find(num-1,x,f[num-1])+find(num-1,1,y-f[num-1]); else cnt+=find(num-1,x,y); } else cnt+=find(num-2,x-f[num-1],y-f[num-1]); return cnt; } int main() { freopen("infinit.in","r",stdin); freopen("infinit.out","w",stdout); scanf("%lld",&n); f[1]=ff[1]=1; f[2]=2;ff[2]=1; for(ll i=3;i<=92;i++) { f[i]=f[i-1]+f[i-2]; ff[i]=ff[i-1]+ff[i-2]; } for(ll i=1;i<=n;i++) { scanf("%lld%lld",&a,&b); ll ans=find(92,a,b); printf("%lld\n",ans); } return 0; }

 

posted @ 2017-10-12 16:44  HolseLee  阅读(563)  评论(0编辑  收藏  举报