bzoj3529 数表 莫比乌斯反演&树状数组

bzoj3529 数表 莫比乌斯反演&树状数组_第1张图片

       然后按照f[i]和a分别排序之后离线插入用树状数组维护前缀和即可。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 100005
using namespace std;

int cnt,pt,mx,p[N],mu[N],c[N],prm[N],ans[N];
struct node{ int x,y,k,id; }a[N],f[N];
int read(){
	int x=0,fu=1; char ch=getchar();
	while (ch<'0' || ch>'9'){ if (ch=='-') fu=-1; ch=getchar(); }
	while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
	return x*fu;
}
void add(int x,int t){
	for (; x<=mx; x+=x&-x) c[x]+=t;
}
int getsum(int x){
	int t=0; for (; x; x-=x&-x) t+=c[x]; return t;
}
bool cmp(node u,node v){ return u.k<v.k; }
void pfs(){
	int i,j,k; f[1].k=f[1].id=mu[1]=1;
	for (i=2; i<=mx; i++){
		f[i].id=i;
		if (!p[i]){ f[i].k=i+1; mu[i]=-1; prm[++cnt]=p[i]=i; }
		for (j=1; j<=cnt && i*prm[j]<=mx; j++){
			k=i*prm[j];
			if (i%prm[j]){
				mu[k]=-mu[i]; p[k]=prm[j]; f[k].k=f[i].k*f[prm[j]].k;
			} else{
				mu[k]=0; p[k]=p[i]*prm[j];
				if (p[k]==k) f[k].k=f[i].k*prm[j]+1; else f[k].k=f[k/p[k]].k*f[p[k]].k;
				break;
			}
		}
	}
	sort(f+1,f+mx+1,cmp);
}
int main(){
	pt=read(); int i;
	for (i=1; i<=pt; i++){
		a[i].x=read(); a[i].y=read();
		a[i].k=read(); a[i].id=i;
		if (a[i].x>a[i].y) swap(a[i].x,a[i].y); mx=max(mx,a[i].x);
	}
	pfs(); sort(a+1,a+pt+1,cmp);
	int j,k,now=1;
	for (i=1; i<=pt; i++){
		for (; now<=mx && f[now].k<=a[i].k; now++)
			for (k=f[now].id; k<=mx; k+=f[now].id) add(k,f[now].k*mu[k/f[now].id]);
		int m=a[i].x,n=a[i].y,last=0,now=0;
		for (j=1; j<=m; j=k+1,last=now){
			k=min(m/(m/j),n/(n/j));
			now=getsum(k);
			ans[a[i].id]+=(now-last)*(m/j)*(n/j);
		}
	}
	for (i=1; i<=pt; i++) printf("%d\n",ans[i]&2147483647);
	return 0;
}


by lych

2016.4.4

你可能感兴趣的:(树状数组,莫比乌斯反演)