BZOJ 3529 SDOI2014 数表 莫比乌斯反演+树状数组

popoqqq大爷有一份不错的题解.

这题是道挺好的莫比乌斯练习题.

做这种类型的题目最需要注意的是理清思路,否则很容易陷进去出不来.

找一个数的因数不是很容易(n0.5),但是我想从它的因数找到它却很容易(均摊logn).

需要注意求和符号的变换.

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iomanip>
using namespace std;
#define LL long long
#define up(i,j,n) for(int i=j;i<=n;i++)
#define pii pair<LL,LL>
#define db double
#define eps 1e-4
#define FILE "dealing"
LL read(){
	LL x=0,f=1,ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0',ch=getchar();}
	return x*f;
}
const LL maxn=401000,inf=1000000000000000LL,limit=(LL)(1e5+0.5),mod=1000000007;
bool cmin(LL& a,LL b){return a>b?a=b,true:false;}
bool cmax(LL& a,LL b){return a<b?a=b,true:false;}
struct node{
	int n,m,a,id,ans;
}a[maxn];
bool cmp(node a,node b){return a.id<b.id;}
bool cmp2(node a,node b){return a.a<b.a;}
int F[maxn],f[maxn],q,prime[maxn],b[maxn],mu[maxn],tail=0;
void getmu(){
	mu[1]=1;
	for(int i=2;i<=limit;i++){
		if(!b[i])prime[++tail]=i,mu[i]=-1;
		for(int j=1;j<=tail&&prime[j]*i<=limit;j++){
			b[i*prime[j]]=1;
			if(i%prime[j])mu[i*prime[j]]=-mu[i];
			else {mu[i*prime[j]]=0;break;}
		}
	}
}
int c[maxn];
int lowbit(LL x){return x&-x;}
void add(LL x,LL d){
	while(x<=limit){
		c[x]+=d;
		x+=lowbit(x);
	}
	return;
}
int getsum(LL x){
	LL ans=0;
	while(x){
		ans+=c[x];
		x-=lowbit(x);
	}
	return ans;
}
pii t[maxn];
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	up(i,1,limit)for(int j=1;j*i<=limit;j++)
		f[i*j]+=i;//求出因数和
	up(i,1,limit)t[i].first=f[i],t[i].second=i;
	sort(t+1,t+limit+1);
	getmu();//求mu函数
	q=read();
	up(i,1,q){
		a[i].n=read(),a[i].m=read(),a[i].a=read();
		a[i].id=i;
		if(a[i].n>a[i].m)swap(a[i].n,a[i].m);
	}//init
	sort(a+1,a+q+1,cmp2);
	int last=1;
	for(int i=1;i<=q;i++){
		int A=a[i].a;
		for(int j=last;t[j].first<=A;j++){
			for(int k=1;k*t[j].second<=limit;k++)
				add(k*t[j].second,t[j].first*mu[k]);
			last=j+1;
		}
		int ans=0,pos=0,n=a[i].n,m=a[i].m;
		for(int j=1;j<=a[i].n;j++){
			pos=min(n/(n/j),m/(m/j));
			ans+=(n/j)*(m/j)*(getsum(pos)-getsum(j-1));
			j=pos;
		}
		a[i].ans=ans;
	}
	sort(a+1,a+q+1,cmp);
	up(i,1,q)printf("%d\n",a[i].ans&((1LL<<31)-1));
	return 0;
}

  

posted @ 2017-03-05 18:52  CHADLZX  阅读(111)  评论(0编辑  收藏  举报