题目大意:
我们按以下方式产生序列:
1、 开始时序列是: “1” ;
2、 每一次变化把序列中的 “1” 变成 “10” ,”0” 变成 “1”。
经过无限次变化,我们得到序列”1011010110110101101…”。
总共有 Q 个询问,每次询问为:在区间A和B之间有多少个1。
任务 写一个程序回答Q个询问
输入 第一行为一个整数Q,后面有Q行,每行两个数用空格隔开的整数a, b。
输出 共Q行,每行一个回答
1 <= Q <= 5000
1 <= a <= b < 2^63
题解:
我们发现,我们
设
f[i,1]表示经过了i-1次变化后序列长度是多少,
f[i,2]则表示这个序列有多少个1。
然后我们发现这题近似斐波那契数列:
f[i,1]=f[i-1,1]+f[i-2,1]
f[i,2]=f[i-1,2]+f[i-2,2]
然后我们发现i最大只能是92,92的时候已经超过了2^63
然后这样以后直接根据[a,b]去分段搜。
C++:
#include
#define LL long long
long long ff[93], a, b;
LL f[93];
int n;
long long find(int p, long long c, long long d)
{
if (c == 0 || d == 0) return 0;
if (p == 1) return 1;
if (p == 2)
{
if (c == 1) return 1;
else return 0;
}
if (c == 1 && d == ff[p]) return f[p];
long long t = 0;
if (c <= ff[p - 1])
{
if (d > ff[p - 1]) t += find(p - 1, c, ff[p - 1]) + find(p - 2, 1, d - ff[p - 1]);
else t += find(p - 1, c, d);
}
else t += find(p - 2, c - ff[p - 1], d - ff[p - 1]);
return t;
}
int main()
{
int n;
scanf("%d", &n);
ff[1] = f[1] = 1;
ff[2] = 2; f[2] = 1;
for (int i = 3; i <= 92; i++)
{
ff[i] = ff[i - 1] + ff[i - 2];
f[i] = f[i - 1] + f[i - 2];
}
for (int i = 1; i <= n; i++)
{
scanf("%lld%lld", &a, &b);
printf("%lld\n", find(92, a, b));
}
}
PASCAL:
var
f:array [0..92,1..2] of qword;
i,j,n:longint;
a,b:qword;
function find(p:longint;c,d:qword):qword;
var
i:longint;
begin
if (c=0) or (d=0) then exit(0);
if p=1 then exit(1);
if p=2 then
if c=1 then exit(1)
else exit(0);
if (c=1) and (d=f[p,1]) then exit(f[p,2]);
find:=0;
if (c<=f[p-1,1])
then begin
if d>f[p-1,1]
then find:=find+find(p-1,c,f[p-1,1])+find(p-2,1,d-f[p-1,1])
else find:=find+find(p-1,c,d);
end
else find:=find+find(p-2,c-f[p-1,1],d-f[p-1,1]);
exit(find);
end;
begin
readln(n);
f[1,1]:=1; f[1,2]:=1;
f[2,1]:=2; f[2,2]:=1;
for i:=3 to 92 do
begin
f[i,1]:=f[i-1,1]+f[i-2,1];
f[i,2]:=f[i-1,2]+f[i-2,2];
end;
for i:=1 to n do
begin
readln(a,b);
writeln(find(92,a,b));
end;
end.