传送门
- 显然枚举
很不好看,我们改成枚举数值,直接莫比乌斯反演
后面提一个出来,是
,而
,故
,故后面一坨就是
,莫队即可
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstring>
#include<algorithm>
#define
#define
#define
#define
using namespace std;
typedef unsigned int ui;
typedef pair<int, ui> piu;
int read(){
int cnt=0, f=1; char ch=0;
while(!isdigit(ch)){ ch=getchar(); if(ch=='-') f=-1; }
while(isdigit(ch)) cnt=cnt*10+(ch-'0'), ch=getchar();
return cnt*f;
}
cs int N = 1e5 + 50;
cs int M = 1e7 + 50;
int T, n, m, a[N];
vector<int> prm; bool isp[M]; int mu[M];
struct qry{ int l, r, c; };
ui as[N], Sum; qry q[N];
vector<piu> d[N];
ui bin[M];
void linear_sieve(int n){
mu[1]=1;
for(int i=2; i<=n; i++){
if(!isp[i]) prm.pb(i), mu[i]=-1;
for(int c:prm){
if(c*i>n) break;
isp[c*i]=true; if(i%c==0) break;
mu[i*c]=-mu[i];
}
}
}
void pre_work(vector<piu> &S, int x){
for(int j=1; j*j<=x; j++){
if(x%j) continue;
if(mu[j]) S.pb(piu(j,j*mu[j]));
bin[j]=bin[x/j]=0;
if(j*j==x) break;
if(mu[x/j]) S.pb(piu(x/j,x/j*mu[x/j]));
}
}
void add(int x){
for(auto c : d[x]){
ui dlt = a[x]/c.fi;
Sum+=(ui)(2*bin[c.fi]+dlt)*dlt*c.se, bin[c.fi]+=dlt;
}
}
void del(int x){
for(auto c : d[x]){
ui dlt = a[x]/c.fi;
bin[c.fi]-=dlt, Sum-=(ui)(2*bin[c.fi]+dlt)*dlt*c.se;
}
}
void Main(){
n=read(), m=read();
for(int i=1; i<=n; i++){
a[i]=read(); d[i].clear();
pre_work(d[i],a[i]);
}
static int blk[N]; int S=sqrt(n);
for(int i=1; i<=n; i++) blk[i]=(i-1)/S+1;
for(int i=1; i<=m; i++){
q[i].l=read(), q[i].r=read(), q[i].c=i;
} sort(q+1, q+m+1, [](cs qry &i, cs qry &j){
return blk[i.l]==blk[j.l]?i.r<j.r:blk[i.l]<blk[j.l];
});
int l=1, r=0; Sum=0;
for(int i=1; i<=m; i++){
while(r<q[i].r) add(++r); while(r>q[i].r) del(r--);
while(l<q[i].l) del(l++); while(l>q[i].l) add(--l);
as[q[i].c] = Sum;
}
for(int i=1; i<=m; i++) cout << as[i] << '\n';
}
int main(){
T=read(); linear_sieve(1e7);
while(T--) Main(); return 0;
}