[莫比乌斯反演+数状数组] BZOJ3529: [Sdoi2014]数表
2017-07-03 11:49
513 查看
题意
有一张N×m的数表,其第i行第j列(1 <=i <=n,1 <=j <=m)的数值为能同时整除i和j的所有自然数之和。给定a,计算数表中不大于a的数之和。
多次询问,输入的第一行一个整数Q表示测试点内的数据组数,接下来Q行,每行三个整数n,m,a(|a| < =10^9)描述一组数据。
n,m,Q <=10^5
题解
设g(i)为gcd(x,y)等于i的数对个数(x<=n,y<=m),显然g(i)=∑i|dμ(di)⌊nd⌋⌊md⌋
设F(i)表示i的约数和,则答案为
∑i=1F(i)g(i)=∑i=1F(i)∗∑i|dμ(di)⌊nd⌋⌊md⌋=∑d=1⌊nd⌋⌊md⌋∑i|dF(i)∗μ(di)
这个F(i) 可以用线性筛搞出来。
还有个条件就是F(i)<=a才对答案有贡献。
思路还是办法把∑i|dF(i)∗μ(di) 的前缀和搞出来。
怎么满足a的约束条件呢?离线搞就行了,把询问按a排序,把F(i)的值从小到大考察,然后用树状数组实现不断的插入F(i)的贡献,维护前缀和。
#include<cstdio> #include<cstring> #include<algorithm> #define Fir first #define Sec second using namespace std; const int maxn=100005, N=100000; int Q,mu[maxn],p[maxn],ans[maxn]; bool vis[maxn]; pair<int,int> F[maxn]; struct data{ int n,m,w,id; bool operator < (const data &b)const{ return w<b.w; } } q[maxn]; void get_mu(){ memset(vis,1,sizeof(vis)); mu[1]=1; for(int i=2;i<=N;i++){ if(vis[i]) p[++p[0]]=i, mu[i]=-1; for(int j=1,k;j<=p[0]&&(k=p[j]*i)<=N;j++){ vis[k]=false; if(i%p[j]==0){ mu[k]=0; break; } mu[k]=-mu[i]; } } } int t1[maxn],t2[maxn]; // t1=(1+p1^1+p1^2+p1^3+...p1^k1) t2=p1^k1 void get_F(){ memset(vis,1,sizeof(vis)); p[0]=0; F[1].Fir=1; for(int i=2;i<=N;i++){ if(vis[i]) p[++p[0]]=i, F[i].Fir=1+i, t1[i]=1+i, t2[i]=i; for(int j=1,k;j<=p[0]&&(k=p[j]*i)<=N;j++){ vis[k]=false; if(i%p[j]==0){ t2[k]=t2[i]*p[j]; t1[k]=t1[i]+t2[k]; F[k].Fir=F[i].Fir/t1[i]*t1[k]; break; } F[k].Fir=F[p[j]].Fir*F[i].Fir; t2[k]=p[j]; t1[k]=1+p[j]; } } for(int i=1;i<=N;i++) F[i].Sec=i; sort(F+1,F+1+N); } int bit[maxn]; void Updata(int x,int val){ for(;x<=N;x+=(x&(-x))) bit[x]+=val; } int Query(int x){ int res=0; for(;x;x-=(x&(-x))) res+=bit[x]; return res; } void Put(int i){ for(int j=1;F[i].Sec*j<=N;j++) Updata(F[i].Sec*j,F[i].Fir*mu[j]); } int main(){ freopen("bzoj3529.in","r",stdin); freopen("bzoj3529.out","w",stdout); get_mu(); get_F(); scanf("%d",&Q); for(int i=1;i<=Q;i++) scanf("%d%d%d",&q[i].n,&q[i].m,&q[i].w), q[i].id=i; sort(q+1,q+1+Q); for(int i=1,last=0;i<=Q;i++){ while(last<N&&F[last+1].Fir<=q[i].w) Put(++last); int res=0, n=q[i].n, m=q[i].m; if(n>m) swap(n,m); for(int d=1,nxt;d<=n;d=nxt+1){ nxt=min(n/(n/d),m/(m/d)); res+=(Query(nxt)-Query(d-1))*(n/d)*(m/d); } ans[q[i].id]=res&0x7fffffff; } for(int i=1;i<=Q;i++) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- [Sdoi 2014] bzoj3529 数表 [莫比乌斯反演+树状数组]
- 【bzoj3529】【SDOI2014】【数表】【莫比乌斯反演+树状数组】
- bzoj 3529: [Sdoi2014]数表 莫比乌斯反演&树状数组
- bzoj 3529: [Sdoi2014]数表 莫比乌斯反演+树状数组
- 3529: [Sdoi2014]数表 莫比乌斯反演+树状数组
- 【BZOJ】3529: [Sdoi2014]数表
- BZOJ 3529([Sdoi2014]数表-莫比乌斯反演)
- [莫比乌斯反演 树状数组] BZOJ 3529 [Sdoi2014]数表
- BZOJ.3529.[SDOI2014]数表(莫比乌斯反演 树状数组)
- bzoj3529: [Sdoi2014]数表 莫比乌斯反演
- 【BZOJ3529】【莫比乌斯反演 + 树状数组】[Sdoi2014]数表
- [BZOJ3529] [SDOI2014] 数表 - 莫比乌斯反演 - 树状数组
- BZOJ 3529: [Sdoi2014]数表 [莫比乌斯反演 树状数组]
- 【BZOJ 3529】 [Sdoi2014]数表
- 【SDOI2014】【BZOJ3529】数表
- BZOJ 3529: [Sdoi2014]数表
- BZOJ 3529: [Sdoi2014]数表 数学 + 莫比乌斯反演 + 取模优化 + 线性筛 + 树状数组
- bzoj 3533 [Sdoi2014]向量集 线段树+凸包+三分(+动态开数组) 好题
- bzoj 3529: [Sdoi2014]数表
- 3529: [Sdoi2014]数表 - BZOJ