洛谷 P2398 GCD SUM || uva11417,uva11426,uva11424,洛谷P1390

https://www.luogu.org/problemnew/show/P2398

$原式=\sum_{k=1}^n(k\sum_{i=1}^n\sum_{j=1}^n[(i,j)=k])$

方法1:

发现暴力枚举k,就变成这道模板题

复杂度O(nlogn)

 1 #pragma GCC optimize("Ofast")
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<vector>
 6 using namespace std;
 7 #define fi first
 8 #define se second
 9 #define mp make_pair
10 #define pb push_back
11 typedef long long ll;
12 typedef unsigned long long ull;
13 typedef pair<int,int> pii;
14 #define N 2000000
15 ll prime[N+100],len,mu[N+100];
16 bool nprime[N+100];
17 ll n,ans,a2;
18 ll F(ll x)    {return (n/x)*(n/x);}
19 int main()
20 {
21     ll i,j,k;
22     mu[1]=1;
23     for(i=2;i<=N;i++)
24     {
25         if(!nprime[i])    prime[++len]=i,mu[i]=-1;
26         for(j=1;j<=len&&i*prime[j]<=N;j++)
27         {
28             nprime[i*prime[j]]=1;
29             if(i%prime[j]==0)    {mu[i*prime[j]]=0;break;}
30             else    mu[i*prime[j]]=-mu[i];
31         }
32     }
33     scanf("%lld",&n);
34     for(k=1;k<=n;k++)
35     {
36         a2=0;
37         for(i=1;i<=n/k;i++)
38             a2+=mu[i]*F(i*k);
39         ans+=a2*k;
40     }
41     printf("%lld",ans);
42     return 0;
43 }

方法2:

https://www.luogu.org/blog/Cinema/solution-p1390

(这是一道类似的题的题解)

复杂度好像是O(n*sqrt(n))?(然而跑的飞快,比nlogn快到不知道哪里去?)


方法3:

$\sum_{i=1}^n\sum_{j=1}^n[(i,j)=k]=\sum_{i=1}^{n/k}\sum_{j=1}^{n/k}[(i,j)=1]$

$=2*(\sum_{i=1}^{n/k}\sum_{j=1}^{i}[(i,j)=1])-1=2*(\sum_{i=1}^{n/k}\phi(i))-1$

这个欧拉函数的前缀和可以先预处理出来,然后枚举k

复杂度O(n)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 using namespace std;
 6 #define fi first
 7 #define se second
 8 #define mp make_pair
 9 #define pb push_back
10 typedef long long ll;
11 typedef unsigned long long ull;
12 typedef pair<int,int> pii;
13 #define N 2000000
14 ll prime[N+100],len,phi[N+100];
15 ll d[N+100];
16 bool nprime[N+100];
17 ll n,ans;
18 ll F(ll x)    {return (n/x)*(n/x);}
19 int main()
20 {
21     ll i,j,k;
22     phi[1]=1;
23     for(i=2;i<=N;i++)
24     {
25         if(!nprime[i])    prime[++len]=i,phi[i]=i-1;
26         for(j=1;j<=len&&i*prime[j]<=N;j++)
27         {
28             nprime[i*prime[j]]=1;
29             if(i%prime[j]==0)    {phi[i*prime[j]]=phi[i]*prime[j];break;}
30             else    phi[i*prime[j]]=phi[i]*(prime[j]-1);
31         }
32     }
33     for(i=1;i<=N;i++)    d[i]+=d[i-1]+phi[i];
34     scanf("%lld",&n);
35     for(k=1;k<=n;k++)    ans+=k*(2*d[n/k]-1);
36     printf("%lld",ans);
37     return 0;
38 }

方法4:

注意到方法3第35行的可以用整除分块优化,甚至可以O(n)预处理后每次O(sqrt(n))回答


类似的题(题面并不完全一样)

https://www.luogu.org/problemnew/show/UVA11417

https://www.luogu.org/problemnew/show/UVA11426

https://www.luogu.org/problemnew/show/P1390


https://www.luogu.org/problemnew/show/UVA11424

这题做法稍微有点不一样,因为数据组数多,不能直接每次O(n)回答

可以用方法4水过去

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 using namespace std;
 6 #define fi first
 7 #define se second
 8 #define mp make_pair
 9 #define pb push_back
10 typedef long long ll;
11 typedef unsigned long long ull;
12 typedef pair<int,int> pii;
13 #define N 2000000
14 ll prime[N+100],len,phi[N+100];
15 ll d[N+100];
16 bool nprime[N+100];
17 ll n,ans;
18 ll F(ll x)    {return (n/x)*(n/x);}
19 int main()
20 {
21     ll i,j,k;
22     phi[1]=1;
23     for(i=2;i<=N;i++)
24     {
25         if(!nprime[i])    prime[++len]=i,phi[i]=i-1;
26         for(j=1;j<=len&&i*prime[j]<=N;j++)
27         {
28             nprime[i*prime[j]]=1;
29             if(i%prime[j]==0)    {phi[i*prime[j]]=phi[i]*prime[j];break;}
30             else    phi[i*prime[j]]=phi[i]*(prime[j]-1);
31         }
32     }
33     for(i=1;i<=N;i++)    d[i]+=d[i-1]+phi[i];
34     while(1){
35     scanf("%lld",&n);
36     if(n==0)    break;
37     ans=0;
38     for(i=1;i<=n;i=j+1)
39     {
40         j=min(n,n/(n/i));
41         ans+=(i+j)*(j-i+1)/2*(2*d[n/i]-1);
42     }
43     printf("%lld\n",(ans-(n+1)*n/2)/2);}
44     return 0;
45 }

或者:

设sum[x]=$\sum_{i=1}^{x-1}(i,x)$

那么询问为n时,答案就是$\sum_{i=1}^n{sum[i]}$

而sum[x]=$\sum_{k=1}^{x-1}(k*\sum_{i=1}^{x-1}[(i,x)=k])$

显然只有当k是x的因子且k不等于x时才能有贡献

枚举k,$\sum_{i=1}^{x-1}[(i,x)=k]=\sum_{i=1}^{\frac{x}{k}-1}[(i,\frac{x}{k})=1]$

$=(\sum_{i=1}^{\frac{x}{k}}[(i,\frac{x}{k})=1])=\phi(\frac{x}{k})$

可以看出来sum[x]=$(\sum_{d|x且d{\neq}x}(d*\phi(\frac{x}{d})))$

实际实现时可以把枚举因子变为枚举倍数

复杂度所有数据加起来O(nlogn+q)

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #include<vector>
 5 using namespace std;
 6 #define fi first
 7 #define se second
 8 #define mp make_pair
 9 #define pb push_back
10 typedef long long ll;
11 typedef unsigned long long ull;
12 typedef pair<int,int> pii;
13 #define N 200000
14 ll prime[N+100],len,phi[N+100];
15 ll sum[N+100];
16 bool nprime[N+100];
17 ll n,ans[N+100];
18 int main()
19 {
20     ll i,j,k;
21     phi[1]=1;
22     for(i=2;i<=N;i++)
23     {
24         if(!nprime[i])    prime[++len]=i,phi[i]=i-1;
25         for(j=1;j<=len&&i*prime[j]<=N;j++)
26         {
27             nprime[i*prime[j]]=1;
28             if(i%prime[j]==0)    {phi[i*prime[j]]=phi[i]*prime[j];break;}
29             else    phi[i*prime[j]]=phi[i]*(prime[j]-1);
30         }
31     }
32     for(i=1;i<=N;i++)
33         for(j=2*i;j<=N;j+=i)
34             sum[j]+=i*phi[j/i];
35     for(i=1;i<=N;i++)    ans[i]=ans[i-1]+sum[i];
36     while(1){
37     scanf("%lld",&n);
38     if(n==0)    break;
39     printf("%lld\n",ans[n]);
40     }
41     return 0;
42 }

猜你喜欢

转载自www.cnblogs.com/hehe54321/p/9315244.html
今日推荐