4804: 欧拉心算
Description
给出一个数字N
Input
第一行为一个正整数T,表示数据组数。
接下来T行为询问,每行包含一个正整数N。
T<=5000,N<=10^7
Output
按读入顺序输出答案。
Sample Input
1
10
10
Sample Output
136
思路:
考虑化简原式,设gcd(i,j) = p
则原式可化为
$sumlimits_{p=1}^{n} sumlimits_{i=1}^{n} sumlimits_{j=1}^{n} varphi(p)[gcd(i,j)=p]$
由于$varphi(p)$和i、j均无关,故我们可以把$varphi(p)$提到前面化为
$sumlimits_{p=1}^{n} varphi(p)sumlimits_{i=1}^{n} sumlimits_{j=1}^{n}[gcd(i,j)=p]$
考虑把$[gcd(i,j)=p]$ 中的p除到前面,则原式可化为
$sumlimits_{p=1}^{n} varphi(p)sumlimits_{i=1}^{lfloor n/p floor} sumlimits_{j=1}^{lfloor n/p floor}[gcd(i,j)=1]$
这时我们设一个函数f(n) 表示 $sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}[gcd(i,j)=1]$
则原式可视为 $sumlimits_{p=1}^{n} varphi(p)*f(lfloor n/p floor)$
考虑化简函数f(n) 。我们发现这个函数和欧拉函数相当相像。首先我们只考虑$ige j$的情况;
即为
$sumlimits_{p=1}^{n} sumlimits_{i=1}^{n} sumlimits_{j=1}^{n} varphi(p)[gcd(i,j)=p]$
由于$varphi(p)$和i、j均无关,故我们可以把$varphi(p)$提到前面化为
$sumlimits_{p=1}^{n} varphi(p)sumlimits_{i=1}^{n} sumlimits_{j=1}^{n}[gcd(i,j)=p]$
考虑把$[gcd(i,j)=p]$ 中的p除到前面,则原式可化为
$sumlimits_{p=1}^{n} varphi(p)sumlimits_{i=1}^{lfloor n/p floor} sumlimits_{j=1}^{lfloor n/p floor}[gcd(i,j)=1]$
这时我们设一个函数f(n) 表示 $sumlimits_{i=1}^{n}sumlimits_{j=1}^{n}[gcd(i,j)=1]$
则原式可视为 $sumlimits_{p=1}^{n} varphi(p)*f(lfloor n/p floor)$
考虑化简函数f(n) 。我们发现这个函数和欧拉函数相当相像。首先我们只考虑$ige j$的情况;
即为
$sumlimits_{i=1}^{n} sumlimits_{j=1}^{i}[gcd(i,j)=1] => sumlimits_{i=1}^{n}varphi(i)$
同理,我们发现只考虑$ile j$的情况,
也为$sumlimits_{j=1}^{n}varphi(j)$
两种情况同时考虑,发现有一种$i=j$的情况重复,故$f(n)$最终可化简为$2 imessumlimits_{i=1}^{n}varphi(i) -1$
综上所述,我们可以发现$ans = sumlimits_{p=1}^{n} varphi(p) imes ( (2 imessumlimits_{i=1}^{n}varphi(i)) -1)$
现在我们有了一个$O(2 imes n)$的方法求解$ans$ 但是数据组数为$T = 5000$ .
同理,我们发现只考虑$ile j$的情况,
也为$sumlimits_{j=1}^{n}varphi(j)$
两种情况同时考虑,发现有一种$i=j$的情况重复,故$f(n)$最终可化简为$2 imessumlimits_{i=1}^{n}varphi(i) -1$
综上所述,我们可以发现$ans = sumlimits_{p=1}^{n} varphi(p) imes ( (2 imessumlimits_{i=1}^{n}varphi(i)) -1)$
现在我们有了一个$O(2 imes n)$的方法求解$ans$ 但是数据组数为$T = 5000$ .
我们需要更加优化的方法才能解决问题,
刚刚的2 * n中有一个n是预处理出$varphi()$以及其前缀和。
是不和T相乘的,故我们考虑把每个答案$O(sqrt n)$处理
发现在处理$s[lfloor n/p floor]$中,$lfloor n/p floor$在每一段的值都是相同的,共有约$sqrt n$段,
发现在处理$s[lfloor n/p floor]$中,$lfloor n/p floor$在每一段的值都是相同的,共有约$sqrt n$段,
而根据乘法结合律,我们可以先把$varphi()$加到一起,
再来乘这个相等的s。s是在预处理中做好的,
故总的时间复杂度为$O(2 imes n + T imes sqrt n)$
下面附上代码
下面附上代码
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N = 10000001; int phi[N+10], pr[N+10], tot; bool np[N+10]; long long s[N+10]; void getphi() { int i, j; phi[1] = 1; for(i=2;i<=N;i++) { if(!np[i]) { pr[++tot] = i; phi[i] = i-1; } for(j=1;j<=tot&&i*pr[j]<=N;j++) { np[i*pr[j]]=1; if(i%pr[j] == 0) { phi[i*pr[j]]=phi[i]*pr[j]; break; } else phi[i*pr[j]]=phi[i]*(pr[j] - 1); } } for(i=1;i<=N;i++) { s[i]=s[i-1]+phi[i]; } } int main() { int t; scanf("%d",&t); getphi(); while(t--) { int n; long long ans=0; scanf("%d",&n); int lst =0; for(int p=1;p<=n;p=lst+1) { lst = n/(n/p); ans+=(s[lst]-s[p-1])*(s[n/p]*2-1); } printf("%lld ",ans); } }
欢迎来原博客看看>原文链接<
特别感谢同届神犇@fcwww 给我的帮助