最大公约数

来源:互联网 发布:彩虹6号围攻帧数优化 编辑:程序博客网 时间:2024/06/15 05:14

Description

  小菜的妹妹小诗就要读小学了!正所谓计算机要从娃娃抓起,小菜决定在幼儿园最后一段轻松的时间里教妹妹编程。
  小菜刚教完gcd即最大公约数以后,一知半解的妹妹写了如下一段代码:
   sum:=0;
   for i:=1 to n-1 do
   for j:=i+1 to n do sum:=sum+gcd(i,j)
  显然这个程序的效率是很低的,小明打算写一个更强的程序,在求出sum的同时比妹妹跑的更快。

Input

  第一行一个整数t,即表示有t组数据
  接下来t行,每行一个整数n

Output

  t行,每行一个整数,表示n所对应的sum值

Sample Input

2
10
100

Sample Output

67
13015

Data Constraint

【数据规模】
  20%数据t≤100,n≤100
  40%数据t≤1000,n≤2000
  100%数据t≤10000,n≤1000000

小结

这题,暴力超水,直接给你程序,但只有20分;
40分就加个优化,f[i]表示你这个数已经求过与i+1~f[i]的gcd和了,但这样子,我们需要保证数据是单调上升的不然会错,于是就要排个序。
100分就要考虑一下了:
题目其实就是求

i=1n1j=i+1ngcd(i,j)

转换一下就是
i=2nj=1i1gcd(i,j)

对吧,于是我们可以设gcd(x,y)=k,移一下项就是gcd(xk,yk)=1这样两个数就互质了,于是,yk的个数就是1~xk中与xk互质的数的个数,就是欧拉公式φ(xk),自然而然,y的个数也是φ(xk)了。
于是,我们考虑可不可以预处理1~1000000的所有φ(i)。我们知道,有一种东西叫线性筛法,可以用来筛素数,于是我们就可以用同样的思想来求这个φ(i)
首先我们找到一个质数就可以更新了,首先自己肯定是φ(i)=i-1.然后枚举j,表示倍数,就是把i当做i*j的质因子,然后我们知道欧拉公式,于是推出:φ(ij)=φ(ij)*(i1i).
最后我们就可以求答案了,用a[i]表示1~i-1中所有数与i的gcd值,然后我们枚举i,枚举倍数j,算出a[i*j]=a[i*j]+i*φ(j)
在算个前缀和,就可以在线输出ans[n];

var        i,j,t,k:longint;        n:int64;        ss:array[0..1000000]of longint;        phi,a,ans:array[0..1000000]of int64;        bz:array[0..1000000]of boolean;function gcd(a,b:longint):longint;begin        if a mod b<>0 then exit(gcd(b,a mod b))        else exit(b);end;begin        for i:=1 to 1000000 do                phi[i]:=i;        for i:=2 to 1000000 do        begin                if bz[i]=false then                        phi[i]:=i-1                else continue;                for j:=2 to 1000000 div i do                begin                        bz[i*j]:=true;                        phi[i*j]:=phi[i*j]*(i-1) div i;                end;        end;        for i:=1 to 1000000 do                for j:=2 to 1000000 div i do                        a[i*j]:=a[i*j]+i*phi[j];        for i:=1 to 1000000 do                ans[i]:=ans[i-1]+a[i];        readln(t);        for i:=1 to t do        begin                readln(n);                writeln(ans[n]);        end;end.
原创粉丝点击