bzoj 2005 NOI 2010 能量采集

我们发现对于一个点(x,y),与(0,0)连线上的点数是gcd(x,y)-1

那么这个点的答案就是2*gcd(x,y)-1,那么最后的答案就是所有点

的gcd值*2-n*m,那么问题转化成了求每个点的gcd值的Σ

也即:Σi<=n Σj<=m gcd(i,j)

那么首先我们知道Σphi(d) d|n=n,所以我们可以将这个式子转化成

Σi<=n Σj<=m Σ d|gcd(i,j) phi(d)

那么对于矩阵n*m来说,我们将phi(d)累加了floor(n/d)*floor(m/d)次

所以对于所有的d,答案就是Σ d<=min(n,m) floor(n/d)*floor(m/d)*phi(d)

我们可以线性筛出欧拉函数表,然后线性的求解。

/**************************************************************
    Problem: 2005
    User: BLADEVIL
    Language: Pascal
    Result: Accepted
    Time:36 ms
    Memory:2568 kb
****************************************************************/
 
//By BLADEVIL
var
    i, j                                :longint;
    prime, mindiv, phi                  :array[0..100010] of int64;
    ans                                 :int64;
    n, m                                :int64;
     
procedure swap(var a,b:int64);
var
    c                                   :int64;
begin
    c:=a; a:=b; b:=c;
end;
 
begin
    read(n,m);
    if n>m then swap(n,m);
    phi[1]:=1;
    for i:=2 to n do
    begin
        if mindiv[i]=0 then
        begin
            inc(prime[0]);
            prime[prime[0]]:=i;
            mindiv[i]:=i;
            phi[i]:=i-1;
        end;
        for j:=1 to prime[0] do
        begin
            if i*prime[j]>m then break;
            mindiv[i*prime[j]]:=prime[j];
            if i mod prime[j]=0 then
            begin
                phi[i*prime[j]]:=phi[i]*prime[j];
                break;
            end else
                phi[i*prime[j]]:=phi[i]*(prime[j]-1);
        end;
    end;
    for i:=1 to n do
        ans:=ans+(n div i)*(m div i)*phi[i];
    ans:=ans*2-n*m;
    writeln(ans);
end.

 

posted on 2013-12-23 16:44  BLADEVIL  阅读(372)  评论(0编辑  收藏  举报