题目简述
求解下列式子:
∑
i
=
1
n
∑
j
=
1
i
−
1
(
a
i
,
a
j
)
×
(
n
−
i
)
\sum_{i=1}^n \sum_{j=1}^{i-1} (a_i,a_j)\times(n-i)
i=1∑nj=1∑i−1(ai,aj)×(n−i)
n ≤ 8 e 4 , a i ≤ 1 e 5 n≤8e4,a_i≤1e5 n≤8e4,ai≤1e5
思路1
写反演写魔怔了,所以上来直接一个反演
最后的式子是这样的
∑
i
=
1
n
(
n
−
i
)
∑
d
∣
a
i
ϕ
(
d
)
c
n
t
d
,
i
\sum_{i=1}^n (n-i) \sum_{d|a_i} \phi(d)cnt_{d,i}
i=1∑n(n−i)d∣ai∑ϕ(d)cntd,i
其中
c
n
t
d
,
i
=
∑
j
=
1
i
−
1
[
d
∣
a
j
]
cnt_{d,i}=\sum_{j=1}^{i-1}[d|a_j]
cntd,i=j=1∑i−1[d∣aj]
显然
i
i
i 那维可以省略
预处理所有
a
i
a_i
ai 的因数(调和级数),在求答案过程中顺便求
c
n
t
cnt
cnt
时间复杂度
O
(
m
+
m
l
o
g
m
+
128
n
)
O(m+mlogm+128n)
O(m+mlogm+128n)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+7,inf=2e12;
int phi[N];
bool bz[N];
vector<int> p,D[N];
void init(int n)
{
phi[1]=1;
for(int i=2; i<=n; i++)
{
if(!bz[i])
{
p.push_back(i);
phi[i]=i-1;
}
for(auto x:p)
{
if(x*i>n) break;
bz[x*i]=1;
if(i%x==0)
{
phi[x*i]=phi[i]*x;
break;
}
else
phi[x*i]=phi[i]*(x-1);
}
}
for(int i=1; i<=n; i++)
{
for(int j=i; j<=n; j+=i)
{
D[j].push_back(i);
}
}
}
void O_o()
{
int n;
cin>>n;
vector<int> a(n+1),cnt(N);
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
sort(a.begin()+1,a.end());
int ans=0;
for(int i=1; i<=n; i++)
{
for(auto d:D[a[i]])
{
ans+=(n-i)*phi[d]*cnt[d];
cnt[d]++;
}
}
cout<<ans<<"\n";
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cout<<fixed<<setprecision(2);
int T=1;
init(100001);
cin>>T;
while(T--)
{
O_o();
}
}
思路2(正常做法)
别看到 gcd 就反演,这题明显不用反演。
令
f
d
f_d
fd 为
g
c
d
gcd
gcd 为
d
d
d 的
(
a
i
,
a
j
)
(a_i,a_j)
(ai,aj) 乘上
(
n
−
i
)
(n-i)
(n−i) 之和,即
f
d
=
∑
i
=
1
n
∑
j
=
1
i
−
1
[
(
i
,
j
)
=
d
]
×
(
n
−
i
)
f_d=\sum_{i=1}^n\sum_{j=1}^{i-1} [(i,j)=d]\times(n-i)
fd=i=1∑nj=1∑i−1[(i,j)=d]×(n−i)
直接求会有重复的问题,不好求,所以很自然的想到容斥。
令
g
d
g_d
gd 为
g
c
d
gcd
gcd 为
k
×
d
k\times d
k×d 的
(
a
i
,
a
j
)
(a_i,a_j)
(ai,aj) 乘上
(
n
−
i
)
(n-i)
(n−i) 之和,即
g
d
=
∑
i
=
1
n
∑
j
=
1
i
−
1
[
d
∣
(
i
,
j
)
]
×
(
n
−
i
)
g_d=\sum_{i=1}^n\sum_{j=1}^{i-1} [d|(i,j)]\times(n-i)
gd=i=1∑nj=1∑i−1[d∣(i,j)]×(n−i)
那么
f
d
=
g
d
−
∑
i
=
d
×
2
f
i
f_d=g_d-\sum_{i=d\times2}f_i
fd=gd−i=d×2∑fi
答案就是
a
n
s
=
∑
i
=
1
i
×
f
i
ans=\sum_{i=1}i\times f_i
ans=i=1∑i×fi
同样需要预处理所有 a i a_i ai 的因数,但不需要线性筛,时间复杂度是一样的。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+7,inf=2e12;
vector<int> p,D[N];
void init(int n)
{
for(int i=1; i<=n; i++)
{
for(int j=i; j<=n; j+=i)
{
D[j].push_back(i);
}
}
}
void O_o()
{
int n;
cin>>n;
vector<int> a(n+1),cnt(N),dp(N);//dp[i]: gcd 为 i 的倍数的贡献
for(int i=1; i<=n; i++)
{
cin>>a[i];
}
sort(a.begin()+1,a.end());
int ans=0;
for(int i=1; i<=n; i++)
{
for(auto d:D[a[i]])
{
dp[d]+=cnt[d]*(n-i);
cnt[d]++;
}
}
//通过容斥,把 dp[i] 变成 gcd 为 i 的贡献
for(int i=N-6; i>=1; i--)
{
for(int j=i*2; j<=N-6; j+=i)
{
dp[i]-=dp[j];
}
ans+=i*dp[i];
}
cout<<ans<<"\n";
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
cout<<fixed<<setprecision(2);
int T=1;
init(100001);
cin>>T;
while(T--)
{
O_o();
}
}