【NOIP2016提高A组模拟9.4】快速荷叶叶变换

来源:互联网 发布:网络策划推广公司 编辑:程序博客网 时间:2024/04/28 09:01

题目

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.
0 0
原创粉丝点击