两道与二进制有关的sequence

题目(第四题第五题)

题目有两个操作,x/2和x-1,很容易就想到和二进制有关,但具体关系是什么呢。

可以考虑x/2和x-1都是左移的操作,于是就可以发现X开头的有趣数列中的数都是x的二进制前缀。

例如 111 110 11 10 1 0

那么判断[a,b]中的有趣数列是不是含有k,只需要把k当做前缀然后取和区间[a,b]相交的部分就可以了。

这个程序写得好丑= =。

View Code
 1 program Neayo;
 2 const
 3         inf='sequence.in';
 4         ouf='sequence.out';
 5 var
 6         i,j,t:longint;
 7         k,a,b,ans,kk:int64;
 8 function min(a,b:int64):int64;
 9 begin
10      if a<b then exit(a) else exit(b);
11 end;
12 procedure init;
13 begin
14      assign(input,inf);assign(output,ouf);
15      reset(input);rewrite(output);
16      readln(t);
17      for t:=1 to t do
18      begin
19           readln(k,a,b);
20           ans:=0;
21           if k>=b then
22           begin
23                if k>b then writeln(0) else writeln(1);
24                continue;
25           end;
26           if k=0 then
27           begin
28                writeln(b-a+1);
29                continue;
30           end;
31           if k>=a then
32           begin
33                a:=k;
34                inc(ans);
35                if (not odd(k))and(k+1<=b)then inc(ans);
36           end;
37           kk:=k;
38           if not odd(kk) then
39           begin
40                kk:=kk+1;
41                if (kk>=a)and(k<a) then inc(ans);
42           end;
43           while k<b do
44           begin
45                k:=k shl 1;
46                kk:=(kk shl 1)+1;
47                if k>b then break;
48                if k>=a then ans:=ans+min(kk,b)-k+1;
49                if (k<a)and(kk>=a) then ans:=ans+min(kk,b)-a+1;
50           end;
51           writeln(ans);
52      end;
53      close(input);
54 end;
55 begin
56      init;
57      close(output);
58 end.

乍一看和上一道题好像。。。

贪心地分析可发现至少需要减max次(max为初始序列中最大的数),至多也只要减max次。因为如果把最大的数*2的话显然会增多很多次数。

于是有这样一个性质x-a/y-a是随着a的增大而减小的,那么对于那些x/max>1/2的数字,总会有个时候使x-a/max-a=1/2,那么我们只需要对它们*2就行了。

对于比max/2还要小的数,就先把它们变得比max/2大,再按照相同步骤处理。

View Code
program Neayo;
const
        inf='sequence.in';
        ouf='sequence.out';
var
        i,j,k,n:longint;
        max,ans:int64;
        half,tmp:extended;
        a:array[0..200001]of int64;

procedure init;
begin
     assign(input,inf);assign(output,ouf);
     reset(input);rewrite(output);
     readln(n);
     for i:=1 to n do
     begin
          readln(a[i]);
          if a[i]>max then max:=a[i];
     end;
     tmp:=max;half:=tmp/2;
     for i:=1 to n do
     if a[i]<max then
     begin
          tmp:=a[i];
          inc(ans);
          while tmp<half do
          begin
               tmp:=tmp*2;
               inc(ans);
          end;
     end;
     inc(ans,max);
     writeln(ans);
     close(input);
end;

begin
     init;
     close(output);
end.
posted @ 2012-11-06 17:10  neayo  阅读(181)  评论(0编辑  收藏  举报