D e s c r i p t i o n Description Description
我们按以下方式产生序列:
1、 开始时序列是: “1” ;
2、 每一次变化把序列中的 “1” 变成 “10” ,“0” 变成 “1”。
经过无限次变化,我们得到序列"1011010110110101101…"。
总共有 Q 个询问,每次询问为:在区间A和B之间有多少个1。
任务 写一个程序回答Q个询问
I n p u t Input Input
第一行为一个整数Q,后面有Q行,每行两个数用空格隔开的整数a, b。
O u t p u t Output Output
共Q行,每行一个回答
S a m p l e Sample Sample I n p u t Input Input
1
2 8
S a m p l e Sample Sample O u t p u t Output Output
4
H i n t Hint Hint
1 <= Q <= 5000
1 <= a <= b < 2^63
T r a i n Train Train o f of of T h o u g h t Thought Thought
首先看那个序列,可以发现它是按照斐波那契数列的形式递增的
然后我们就可以加入前缀和发现:
f
[
a
,
b
]
=
q
[
b
]
−
q
[
a
−
1
]
f[a,b]=q[b]-q[a-1]
f[a,b]=q[b]−q[a−1]
然后用递归求前缀和就好了
C o d e Code Code
#include<cstdio>
#include<iostream>
using namespace std;
long long f[1005][2],Q; long long a,b;
long long work(long long x)
{
if (x==0) return 0;
for (int i=0; i<=100; ++i)
{
if (x==f[i][1]) return f[i][0];//看是否符合长度
else if (x<f[i][1]) return f[i-1][0]+work(x-f[i-1][1]);//继续递归
}
}
int main()
{
scanf("%lld",&Q);
f[0][0]=1; f[0][1]=1;//f[0][0]为序列中1的个数
f[1][0]=1; f[1][1]=2;//f[0][1]为序列的长度
for (int i=2; i<=100; ++i)
f[i][0]=f[i-1][0]+f[i-2][0],f[i][1]=f[i-1][1]+f[i-2][1];
for (int i=1; i<=Q; ++i)
{
scanf("%lld%lld",&a,&b);
printf("%lld\n",work(b)-work(a-1));
}
return 0;
}