【HDU6711】Touma Kazusa's function(莫比乌斯反演)(莫队)

传送门

  • 显然枚举 a i , a j a_i,a_j ai,aj 很不好看,我们改成枚举数值,直接莫比乌斯反演
    A n s = ∑ d n d φ ( d ) ∑ i n / d ∑ j n / d i j [ ( i , j ) = 1 ] c n t i d c n t j d = ∑ d d φ ( d ) ∑ l n / d μ ( l ) ( ∑ l ∣ i i c n t i d ) ( ∑ l ∣ j j c n t j d ) = ∑ d d φ ( d ) ∑ l μ ( l ) l 2 ( ∑ i n / d l i c n t i d l ) 2 = ∑ T ( ∑ i n / T i c n t i T ) 2 ( ∑ d ∣ T d φ ( d ) μ ( T d ) ( T d ) 2 ) Ans=\sum_d^n d\varphi(d)\sum_i^{n/d}\sum_j^{n/d}ij[(i,j)=1]cnt_{id}cnt_{jd}\\=\sum_d d\varphi(d)\sum_{l}^{n/d}\mu(l)(\sum_{l|i}icnt_{id})(\sum_{l|j}jcnt_{jd})\\=\sum_dd\varphi(d)\sum_l\mu(l)l^2(\sum_{i}^{n/dl}icnt_{idl})^2\\=\sum_T(\sum_i^{n/T}icnt_{iT})^2(\sum_{d|T}d\varphi(d)\mu(\frac{T}{d})(\frac{T}{d})^2) Ans=dndφ(d)in/djn/dij[(i,j)=1]cntidcntjd=ddφ(d)ln/dμ(l)(liicntid)(ljjcntjd)=ddφ(d)lμ(l)l2(in/dlicntidl)2=T(in/TicntiT)2(dTdφ(d)μ(dT)(dT)2)
    后面提一个 T T T 出来,是 ( μ ⋅ I d ) ∗ φ (\mu \cdot Id)*\varphi (μId)φ,而 ( μ ⋅ I d ) ∗ φ ∗ I = ( μ ⋅ I d ) ∗ I d = e (\mu \cdot Id)*\varphi*I=(\mu \cdot Id)*Id=e (μId)φI=(μId)Id=e,故 ( μ ⋅ I d ) ∗ φ = μ (\mu \cdot Id)*\varphi=\mu (μId)φ=μ,故后面一坨就是 T μ ( T ) T\mu(T) Tμ(T),莫队即可
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstring>
#include<algorithm>
#define cs const
#define pb push_back
#define fi first
#define se second
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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FSYo

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值