题意:给出n,求:
[sum_{i=1}^{n-1}sum_{j=i+1}^{n}gcd(i,j)
]
多组数据,(n<=4*10^6)
sol
今天心血来潮再来写一写式子
首先这里求的是无序对而且还不能相等所以说我第一遍样例都没过
那么如果你求出了(sum_{i=1}^{n}sum_{j=1}^{n}gcd(i,j)),你就只要把这个答案减去(sum_{i=1}^{n}i)再除以二就可以了。你可以当做是,你求出的那个东西就是一整个矩阵的和,而题目要求的只是正对角线上方的部分,所以减掉对角线上的再除以2就是答案。
接下来开始大力开式子(接下来我们求的是(sum_{i=1}^{n}sum_{j=1}^{n}gcd(i,j)))。
[ans=sum_{d=1}^{n}d*sum_{i=1}^{n}sum_{j=1}^{n}[gcd(i,j)==d]
]
[=sum_{d=1}^{n}d*sum_{i=1}^{n/d}sum_{j=1}^{n/d}[gcd(i,j)==1]
]
[=sum_{d=1}^{n}d*sum_{i=1}^{n/d}mu(i)lfloorfrac n{id}
floor^2
]
[=sum_{T=1}^{n}lfloorfrac nT
floor^2sum_{d|T}d*mu(frac Td)
]
然后线性筛这个函数
[h(T)=sum_{d|T}d*mu(frac Td)
]
求一个前缀和然后分块T
复杂度(O(n+Tsqrt n))
code
#include<cstdio>
#include<algorithm>
using namespace std;
#define ll long long
const int N = 4000000;
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
int pri[N+5],tot,zhi[N+5];
ll low[N+5],h[N+5];
void Mobius()
{
zhi[1]=low[1]=1;h[1]=1;
for (int i=2;i<=N;i++)
{
if (!zhi[i]) low[i]=pri[++tot]=i,h[i]=i-1;
for (int j=1;j<=tot&&i*pri[j]<=N;j++)
{
zhi[i*pri[j]]=1;
if (i%pri[j]==0)
{
low[i*pri[j]]=low[i]*pri[j];
if (low[i]==i)
h[i*pri[j]]=h[i]*pri[j];
else
h[i*pri[j]]=h[i/low[i]]*h[low[i]*pri[j]];
break;
}
low[i*pri[j]]=pri[j];
h[i*pri[j]]=h[i]*h[pri[j]];
}
}
for (int i=1;i<=N;i++)
h[i]+=h[i-1];
}
int main()
{
Mobius();
while (233)
{
int n=gi(),i=1;
if (n==0) break;
ll ans=0;
while (i<=n)
{
int j=n/(n/i);
ans+=(h[j]-h[i-1])*(n/i)*(n/i);
i=j+1;
}
printf("%lld
",(ans-1ll*(n+1)*n/2)/2);
}
return 0;
}