【bzoj3529】[Sdoi2014]数表

来源:互联网 发布:slackware安装软件 编辑:程序博客网 时间:2024/05/16 05:00

http://www.lydsy.com/JudgeOnline/problem.php?id=3529
最近文化课血崩没太多时间打题
这道题目算是莫比乌斯反演的入门题了
q次询问,每次询问给定n,m,a,求
这里写图片描述
然后这个东西怎么求呢,我们试着化简一下
我们假设n<=m
∑i=1…n∑j=1…m F(gcd(i,j))*[F(gcd(i,j))<=a]
=∑d=1..n F(d)[F(d)<=a] ∑i=1…n∑j=1…m gcd(i,j)==d
=∑d=1..n F(d)[F(d)<=a] ∑x=1…[n/d] μ(x)[n/dx][m/dx]
=∑T=1..n [n/T][m/T] ∑d|T F(d)[F(d)<=a]μ(T/d)
然后我们可以按[n/T][m/T]分块,然后就转化为求∑d|T F(d)[F(d)<=a]μ(T/d)的前缀和
这个[F(d)<=a]特别地麻烦,我们考虑把它去掉
我们可以对所有在1-100000的数的F值和所有询问的a进行排序
那么问题转化为了,修改一个数的F值,求一个前缀的∑d|T F(d)*μ(T/d)
显然每一个数都只会被修改一次,所以我们可以修改每个数的时候修改它所有的倍数,根据调和级数,修改的次数是NlnN级别的
那么就是一个单点修改查询前缀和的问题啦,我们可以用树状数组来做
然后注意我们要先预处理莫比乌斯函数和约数和函数
这个时候蒟蒻hsz突然发现自己好像不会O(n)线性筛约数和函数
然后脑补了一波
我们可以记录一个lst,设i的最小质因数是p,那么lst[i]表示i去掉所有的p后的数
首先处理质数的情况,就是lst[i]=1,f[i]=i+1
然后当i % j>0时因为i,j互质根据积性函数的性质可以直接得到f[i*j],然后我们有一个结论,就是欧拉筛筛x是用x的最小质因数来筛的,所以有lst[i*j]=i;
然后当i % j=0时,有f[i*j]=f[i]*j+f[lst[i]];
因为我们设枚举质因数时强制至少选一个j,那么就会枚举到i的所有因数乘上j
然后我们如果一个j都不选,那么就会枚举到i去掉所有的j后的数的所有因数
所以有上面那条式子
蒟蒻hszWA了一发,是因为质数的情况没有把lst[i]赋值,所以以后写线性筛的时候一定要提前想好要筛哪些函数然后每种情况都要对所有用到的函数赋一遍初值
然后思维方面蒟蒻hsz学会了:
筛约数和函数和一类积性函数的筛法,其实也就两种情况,i % j=0和质数的情况如果可以处理就搞完了,然后根据n以内质数只有n/logn个这个小结论,处理质数的情况的时候可以带一个log(有时候压根想不到不带log做法,有时候写起来很麻烦),当然卡常另说。筛一些函数如果直接筛筛不出来可以考虑记录更多的信息,基本上只要是积性函数就可以筛的。
对于mod 2^31的题流行的方法是用int记录答案让int自然溢出,最后和2^31-1取个与,这个方法以前也使用过
小结论:欧拉筛筛x是用x的最小质因数来筛的,也就是说j是i*j的最小质因数,也许这对筛某些函数有帮助
技巧类的,就是多组询问求满足F(d)<=a的情况的题,可以把所有d的F值求出来和a放在一起排序,这样可以转化为动态修改查询问题(通常使用数据结构),然后去掉F(d)<=a这个限制条件。排序往往是很强大的,可以把题目的限制条件降一维然后就不用写一些神奇的数据结构了。也算是灵活运用数据结构吧(这显然是在扯淡……)
最后是AC code:

#include <cstdio>#include <algorithm>using namespace std;struct lwn{    int n,m,w,id,wz;    bool operator < (const lwn &jb)const{        return w<jb.w || w==jb.w && id>jb.id;    }} a[120050];int t,i,miu[100050],f[100050],lst[100050],su[100050],tot,b[20050],j,BIT[100050];bool vis[100050];int main(){    freopen("bzoj3529.in","r",stdin);    freopen("bzoj3529.out","w",stdout);    scanf("%d",&t);    for (i=1;i<=t;i++){        scanf("%d%d%d",&a[i].n,&a[i].m,&a[i].w);a[i].id=1;a[i].wz=i;        if (a[i].n>a[i].m) swap(a[i].n,a[i].m);    }f[1]=1;miu[1]=1;    for (i=2;i<=100000;i++){        if (!vis[i]){            su[++tot]=i;f[i]=i+1;miu[i]=-1;lst[i]=1;        }        for (j=1;j<=tot;j++){            if (i*su[j]>100000) break;            if (i % su[j]){                f[i*su[j]]=f[i]*f[su[j]];lst[i*su[j]]=i;                miu[i*su[j]]=miu[i]*(-1);vis[i*su[j]]=true;            }            else{                f[i*su[j]]=f[i]*su[j]+f[lst[i]];lst[i*su[j]]=lst[i];                miu[i*su[j]]=0;vis[i*su[j]]=true;                break;            }        }    }    for (i=1;i<=100000;i++){        a[++t].n=i;a[t].w=f[i];a[t].id=2;    }sort(a+1,a+t+1);    for (i=1;i<=t;i++) if (a[i].id==1){        int now=1;        while (now<=a[i].n){            int ans1=a[i].n/now,ans2=a[i].m/now,r1=a[i].n/ans1,r2=a[i].m/ans2;if (r1>r2) swap(r1,r2);            for (int y=r1;y>=1;y-=(y & (-y))) b[a[i].wz]+=ans1*ans2*BIT[y];            for (int y=now-1;y>=1;y-=(y & (-y))) b[a[i].wz]-=ans1*ans2*BIT[y];            now=r1+1;        }    }else{        for (j=a[i].n;j<=100000;j+=a[i].n)        for (int y=j;y<=100000;y+=(y & (-y))) BIT[y]+=a[i].w*miu[j/a[i].n];    }for (i=1;i<=t-100000;i++) printf("%d\n",b[i]&2147483647);    return 0;}
1 0
原创粉丝点击