[BZOJ3529]SDOI2014数表|莫比乌斯反演|树状数组

来源:互联网 发布:js怎么取数组的值 编辑:程序博客网 时间:2024/06/04 06:42

要求的是的约数和。。惯用思路,转过来枚举,则有,现在要求的就是,那么如果能处理出的前缀和就可以分块计算辣。。这两个都是积性的可以线性筛出来(我嫌麻烦暴力算的)。。但是还要处理a的限制,把所有询问按a升序排序,i按升序排序,用树状数组维护前缀和,每次把小于当前询问的a的东西加进去就行啦。。(Orz PoPoQQQ)

#include<cstdio>#include<iostream>#include<algorithm>#define N 100005#define inf 0x7fffffffusing namespace std;struct query{int n,m,a,xu;}q[N];struct data{int xu,d;}f[N];int T,i,j,cnt=0,now,mu[N],p[N],ans[N],c[N];bool u[N];int lowbit(int x){return x&-x;}void prepare(){f[1].xu=mu[1]=1;f[1].d=c[1]=0;for (i=2;i<=100000;i++) u[i]=0;for (i=2;i<=100000;i++){f[i].d=0;f[i].xu=i;c[i]=0;if (!u[i]) p[++cnt]=i,mu[i]=-1;for (j=1;j<=cnt&&p[j]*i<=100000;j++){u[p[j]*i]=1;if (i%p[j]==0){mu[i*p[j]]=0;break;}else mu[i*p[j]]=-mu[i];}}for (i=1;i<=100000;i++)for (j=i;j<=100000;j+=i) f[j].d+=i;}bool cmp(query a,query b){return a.a<b.a;}bool cmp2(data a,data b){return a.d<b.d;}void add(int x,int k){for (int i=x;i<=100000;i+=lowbit(i)) c[i]+=k;}int sum(int x){int ans=0;for (int i=x;i;i-=lowbit(i)) ans+=c[i];return ans;}void cal(query x){int ans1=0,last;for (int i=1;i<=min(x.n,x.m);i=last+1){last=min(x.n/(x.n/i),x.m/(x.m/i));ans1+=(sum(last)-sum(i-1))*(x.n/i)*(x.m/i);}ans[x.xu]=ans1;}int main(){prepare();scanf("%d",&T);for (i=1;i<=T;i++)scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].a),q[i].xu=i;sort(q+1,q+1+T,cmp);sort(f+1,f+100001,cmp2);now=0;for (i=1;i<=T;i++){while (now+1<=100000&&f[now+1].d<=q[i].a){now++;for (j=f[now].xu;j<=100000;j+=f[now].xu) add(j,f[now].d*mu[j/f[now].xu]);}cal(q[i]);}for (i=1;i<=T;i++) printf("%d\n",ans[i]&inf);}


0 0
原创粉丝点击