SSL P1861 提高组 无限序列

326 篇文章 0 订阅
83 篇文章 0 订阅

题目大意:
我们按以下方式产生序列:
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 <stdio.h>
#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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值