……一道数学题

【问题描述】

八是个很有趣的数字啊。八=发,八八=爸爸,88=拜拜。当然最有趣的还是8用二进制表示是1000。怎么样,有趣吧。当然题目和这些都没有关系。

某个人很无聊,他想找出[a,b]中能被8整除却不能被其他一些数整除的数。

【输入文件】

输入文件eight.in。第一行一个数n,代表不能被整除的数的个数。第二行n个数,中间用空格隔开。第三行两个数a,b,中间一个空格。

【输出文件】

输出文件eight.out应包含一个整数,为[a,b]间能被8整除却不能被那n个数整数的数的个数。

【样例输入】

3

7764 6082 462

2166 53442

【样例输出】

6378

【数据规模】

对于30%的数据, 1≤n≤5,1≤a≤b≤100000。

对于100%的数据,1≤n≤15,1≤a≤b≤10^9,N个数全都小于等于10000大于等于1。

 

 

从8的倍数中减去其他数的倍数(同时这些数能被8整除)

所以要应用容斥原理 求a1 a2 a3...它们的并集的时候 方法很巧妙= =+

program eight;
var
  v:array[0..16] of boolean;
  a:array[0..16] of int64;
  n:longint;
  l,r,ans,tot:int64;

procedure init;
var i:longint;
begin
  assign(input,'eight.in');reset(input);
  assign(output,'eight.out');rewrite(output);
  fillchar(v,sizeof(v),0);
  readln(n);
  for i:=1 to n do read(a[i]);
  readln(l,r);
end;

function gcd(m,n:int64):int64;
begin
  if (m mod n=0) then exit(n) else exit(gcd(n,m mod n));
end;

procedure search(x:longint);
var i,tem:longint;
    now:int64;                                                       //开始now搞成longint就wa了
begin
  if (x>n) then begin
    tem:=0;
    for i:=1 to n do if v[i] then inc(tem);
    if (tem=0) then exit;
    if (tem mod 2=0) then tem:=-1 else tem:=1;      //奇数个-1偶数个+1
   
    now:=8;                                                         //求当前选的数的最小公倍数
    for i:=1 to n do if v[i] then now:=(now*a[i]) div gcd(now,a[i]);
    tot:=tot+((r div now)-((l-1) div now))*tem;
  end
  else begin
    search(x+1);
    v[x]:=true;
    search(x+1);
    v[x]:=false;
  end;
end;

procedure main;
begin
  ans:=(r div 8)-((l-1) div 8);                     //原来算8的倍数有多少个是这么简单(我傻叉吗!)……
  tot:=0;                                                 //要减去的数
  search(1);
  ans:=ans-tot;
  writeln(ans);
end;

procedure terminate;
begin
  close(input);close(output);
end;

begin
  init;
  main;
  terminate;
end.

posted on 2011-11-03 17:49  ushiojamie  阅读(263)  评论(0编辑  收藏  举报