CF1900D 题解
huangrenheluogu · · 题解
VP 的时候没切,真的太菜了。
容易想到将数组排序,枚举两个数,然后算
首先我们需要知道一个常识:一个数的因数不会很多,好像我以前做的一道题中
所以,我们可以预处理出一个数的因数,并且把
对于一个
怎么求
在处理
那么在处理第
显然,
那么
容斥解决。
注意这里每一个数的因数需要倒序取出,这样才可以保证取
代码如下:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 8e4 + 5, M = 1e5 + 5, maxn = 1e5;
int T, n, a[N], f[M], tem, cnt, ans, qp[M][32], tot, g[M];
vector<int>num[M], c;
inline void init(){
for(int i = 1; i <= maxn; i++) f[i] = g[i] = 0ll;
ans = 0ll;
}
inline int get(int x, int val){
int res = 0;
for(auto xx : num[val / x]){
if(xx != 1) g[x] -= g[x * xx];
}
return g[x];
}
inline void solve(){
for(int i = 1; i < n; i++){
cnt = 0ll;
for(auto x : num[a[i]]){
g[x] = f[x];
cnt += get(x, a[i]) * x;
}
for(auto x : num[a[i]]){
f[x]++;
}
// printf("%d %d\n", i, cnt);
cnt *= (n - i);
ans += cnt;
}
}
inline bool cmp(int x, int y){
return x > y;
}
signed main(){
scanf("%lld", &T);
for(int i = 2; i <= maxn; i++){
qp[i][0] = 1;
for(int j = 1; qp[i][j - 1] <= maxn; j++){
qp[i][j] = qp[i][j - 1] * i;
}
}
num[1].push_back(1);
for(int i = 2; i <= maxn; i++){
tem = i;
tot = 0;
num[i].push_back(1ll);
for(int j = 2; j * j <= i; j++){
if(tem % j) continue ;
cnt = 0;
while(tem % j == 0){
cnt++;
tem /= j;
}
c = num[i];
for(auto x : c){
for(int kk = 1; kk <= cnt; kk++){
num[i].push_back(x * qp[j][kk]);
}
}
}
if(tem > 1){
c = num[i];
for(auto x : c){
num[i].push_back(tem * x);
}
}
sort(num[i].begin(), num[i].end(), cmp);
}
while(T--){
init();
scanf("%lld", &n);
for(int i = 1; i <= n; i++) scanf("%lld", &a[i]);
sort(a + 1, a + n + 1);
solve();
printf("%lld\n", ans);
}
return 0;
}
评测链接