题目
80分
设
F[i]
表示选
N
个数,gcd值为
则
F[i]=(⌈R/i⌉−⌈(L−1)/i⌉)N−ΣF[i∗j](j>1且i∗j<=R)
解释一下。
gcd值为
i
的方案数,就是gcd值为
方案数为在
L R
范围内
i
的倍数中随便选
就是(L~R中i的倍数)的
N
次方。
即
既然保证了选的数一定是
i
的倍数,那么减去
这样搞因为
100分
观察数据范围。
R−L<=105
又可知
gcd(x,y)
一定小于
x−y(x>y)
,
只要选了两个不相同的数,结果一定小于
R−L
。
所以如果gcd值超过
R−L
,说明选的
N
个数一定都相同。
所以可知,
所以,其实只需要修改一下定义,就能让
i
的范围缩小到
重新定义
F[i]
表示选
N
个数,gcd为
因为不能完全相同,所以结果要减去为
(全部选一样只能选一种)。
所以公式变成了
F[i]=(⌈R/i⌉−⌈(L−1)/i⌉)N−(⌈R/i⌉−⌈(L−1)/i⌉)−ΣF[i∗j](j>1且i∗j<=R−L)
因为
F[i]
=总方案数-所有数都相同的方案-不全部相同的方案。
因为最后可能全部选同一种,即K在L~R间,
所以特判+1。
优化
因为题目只要求gcd为K的数,所以可以用F[i]来表示原先的F[i*k],这样可以优化时间。
代码
const
md=1000000007;
var
f:array[1..100000] of longint;
n,m,l,r,l2,r2,ii,i,j,len:longint;
function qpower(a,t:longint):int64;
begin
if t>n then
begin
ii:=n;
exit(1);
end;
qpower:=qpower(a,t*2);
qpower:=qpower*qpower mod md;
if ii>=t then
begin
qpower:=qpower*a mod md;
ii:=ii-t;
end;
end;
begin
assign(Input,'number.in'); reset(Input);
assign(Output,'number.out'); rewrite(Output);
readln(n,m,l,r);
len:=(r div m)-((l-1) div m);//计算边界
for i:=len downto 1 do
begin
l2:=(l-1) div (i*m);//范围优化
r2:=r div (i*m);
f[i]:=qpower(r2-l2,1)-(r2-l2);//计算总方案-只选一种的方案
for j:=2 to len div i do//减去选不止一种的方案
f[i]:=(f[i]-f[i*j]) mod md;
if f[i]<0 then
f[i]:=f[i]+md;
end;
if (l<=m) and (m<=r) then//如果K在LR范围内,说明可以全选K,要特判。
inc(f[1]);
writeln(f[1]);
close(Input); close(Output);
end.