……一道数学题
【问题描述】
八是个很有趣的数字啊。八=发,八八=爸爸,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) 编辑 收藏 举报