bzoj2820(莫比乌斯反演)

来源:互联网 发布:2014网络流行语 编辑:程序博客网 时间:2024/05/18 03:45
神犇YY虐完数论后给傻×kAc出了一题给定N, M,求1<=x<=N, 1<=y<=M且gcd(x, y)为质数的(x, y)有多少对kAc这种

傻×必然不会了,于是向你来请教……多组输入

T = 10000

N, M <= 10000000


这个复杂度,枚举质数都要超时。。

所以将公式转化,线性筛的时候把,预处理出答案是系数,然后就是标准的下底函数分块


难点:

1:公式转化,真心十分巧妙 见hzwer的博客 http://hzwer.com/6142.html

2:线性筛如何筛出系数  


#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<algorithm>using namespace std;typedef long long ll;const int N=10000005;ll n,m;int u[N],p[N],sum[N],f[N];bool b[N];void init(){u[1]=1;for (int i=2;i<N;i++){if (!b[i]) p[++p[0]]=i,u[i]=-1;for (int j=1;j<=p[0]&&p[j]*i<N;j++){b[i*p[j]]=true;if (i%p[j]==0){u[i*p[j]]=0;break;}else u[i*p[j]]=-u[i];}}for (int i=1;i<=p[0];i++)for (int j=1;j*p[i]<N;j++) f[j*p[i]]+=u[j]; for (int i=1;i<N;i++) sum[i]=sum[i-1]+f[i];}ll work(ll n,ll m){ll ans=0;for (int l=1,r;l<=n;l=r+1){r=min(n/(n/l),m/(m/l));ans+=(sum[r]-sum[l-1])*(n/l)*(m/l);}return ans;}int main(){int T;init();scanf("%d",&T);while (T--){scanf("%lld%lld",&n,&m);if (n>m) swap(n,m);printf("%lld\n",work(n,m)); }return 0;}


总结

1:这道题巧妙的将公式进行转化,以便于在询问的时候不用,枚举质数来进行计算。公式转化,实际上这里就是将内层的sigema转移到外层,然后保证整个式子是与之前等价的。

具体来说,公式转化就是,首先要保证转化的公式和原先的公式是等价的,他们的sigema维护的东西是不相同的,但是转化之后可以通过预处理之类的方法降低复杂度(这里就是通过预处理系数降低复杂度的)


2:线性筛法是一个巧妙的东西,这里的线性筛就是来筛系数的





0 0
原创粉丝点击