题目
Description
Input
一行,包含两个整数N,M。
Output
1个整数,FHT(N,M) mod 1000000007的值。
Sample Input
3 4
Sample Output
1
Data Constraint
40%:n,m<=1000
60%:n,m<=106
100%:n,m<=109
比赛时の想法
一开始看到这道题,就想到了60分的做法,然后就开始想log级别或者是根号级别的做法,过了几分钟,突然想到了一个根号级别的做法:
我们设q=n mod i,p=n div i; 那么我们可以分情况进行讨论:
1:p<=n√,这样的情况最多有n√个,我们直接暴力求解
2:对于剩下的还没有处理的数,他们的p值都是<=n√的,对于每一组p值相等的集合A,集合内所有的数是有等差数列的性质的,那么我们就可以先用二分查找到p值相等的区间(l,r),然后直接用等差数列的算法O(1)计算出这一段数对于答案的贡献,这样我们就可以在n√的时间计算出答案了
正解
↑
贴代码
const md=1000000007;
var
n,m,i,j,k:longint;
x,y,ans,tot,l,r,mid:int64;
procedure init;
begin
readln(n,m);
k:=trunc(sqrt(n));
for i:=1 to n do
begin
if n div i<=k then break;
ans:=ans+(n mod i);
end;
ans:=ans mod md;
end;
begin
init;
if (n=1) or (m=1) then
begin
writeln(0);
halt;
end;
for i:=k downto 1 do
begin
l:=1;
r:=n;
while l<r do
begin
mid:=(l+r) div 2;
if n div mid>=i then l:=mid+1 else r:=mid;
end;
x:=1;
y:=l;
while x<y do
begin
mid:=(x+y) div 2;
if n div mid>i then x:=mid+1 else y:=mid;
end;
l:=x;
while n div l<=i do dec(l);
inc(l);
while n div r<i do dec(r);
if n mod l=0 then inc(l);
x:=n mod l;
if n mod r=0 then dec(r);
y:=n mod r;
mid:=r-l+1;
if l>r then continue;
ans:=(ans+((x+y)*mid) div 2) mod md;
end;
k:=trunc(sqrt(m));
for i:=1 to m do
begin
if m div i<=k then break;
tot:=tot+(m mod i);
end;
tot:=tot mod md;
n:=m;
for i:=k downto 1 do
begin
l:=1;
r:=m;
while l<r do
begin
mid:=(l+r) div 2;
if m div mid>=i then l:=mid+1 else r:=mid;
end;
x:=1;
y:=l;
while x<y do
begin
mid:=(x+y) div 2;
if m div mid>i then x:=mid+1 else y:=mid;
end;
l:=x;
while m div l<=i do dec(l);
inc(l);
while m div r<i do dec(r);
if n mod l=0 then inc(l);
x:=m mod l;
if m mod r=0 then dec(r);
y:=m mod r;
mid:=r-l+1;
if l>r then continue;
tot:=(tot+((x+y)*mid) div 2) mod md;
end;
ans:=ans*tot;
writeln(ans mod md);
end.