BZOJ 2818 Gcd + spoj 4491(莫比乌斯反演 分块)

来源:互联网 发布:女朋友漂亮知乎 编辑:程序博客网 时间:2024/05/16 15:54

思路:

数据范围1e7,预处理出miu的前缀和,对于每个素数,反演式求 f(i) 分块,出结果。

拓展:

如果是多组样例,那么预处理F(i) 的系数,每次询问是sqrt(n)的复杂度查询。代码在下方。

#include<stdio.h>#include <iostream>#include<string.h>#include<math.h>#include<algorithm>#define eps 1e-8typedef long long int lli;using namespace std;const int maxn = 1e7+10;bool isprime[maxn];int prime[maxn];char miu[maxn];void moblus(){    int cnt = 0;miu[1] = 1;    for(lli i = 2;i < maxn;i++){        if(!isprime[i]){            prime[cnt++] = i,miu[i] = -1;//phi[i] = i-1;        }        for(lli j = 0;j < cnt && i*prime[j] < maxn;j++){            lli x = prime[j];            isprime[i*x] = 1;            if(i%x){                miu[i*x] = -miu[i];                //phi[i*x] = phi[i] * phi[x];            }            else{                miu[i*x] = 0;                //phi[i*x] = phi[i] * x;                break;            }        }    }}int ff[maxn],sum[maxn];int main(){    moblus();    for(int i = 1;i <= maxn;i++){        sum[i] = sum[i-1] + miu[i];    }    lli a,ans = 0;    scanf("%lld",&a);    for(int i = 2;i <= a;i++){        if(isprime[i]==0){            lli b = a/i,l;            for(int j=1;j<=b;j=l+1){//分块加速                l= b/(b/j);                ans += (lli)(sum[l]-sum[j-1])*(b/j)*(b/j);            }        }    }    printf("%lld\n",ans);    return 0;}

spoj 4491

#include<stdio.h>#include <iostream>#include<string.h>#include<math.h>#include<algorithm>#define eps 1e-8typedef long long int lli;using namespace std;const int maxn = 1e7+10;bool isprime[maxn];int prime[maxn];char miu[maxn];void moblus(){    int cnt = 0;miu[1] = 1;    for(lli i = 2;i < maxn;i++){        if(!isprime[i]){            prime[cnt++] = i,miu[i] = -1;//phi[i] = i-1;        }        for(lli j = 0;j < cnt && i*prime[j] < maxn;j++){            lli x = prime[j];            isprime[i*x] = 1;            if(i%x){                miu[i*x] = -miu[i];                //phi[i*x] = phi[i] * phi[x];            }            else{                miu[i*x] = 0;                //phi[i*x] = phi[i] * x;                break;            }        }    }}int ff[maxn],sum[maxn];int main(){    lli p,q;    scanf("%lld",&q);    moblus();    for(int i = 2;i <= maxn;i++){        if(isprime[i]) continue;        for(lli j = 1;j*i <= maxn;j++){            ff[j*i] += miu[j];        }    }    for(int i = 1;i <= maxn;i++){        sum[i] = sum[i-1] + ff[i];//注意,这里成了F系数的前缀和了    }    while(q--){        lli a,b;        scanf("%lld%lld",&a,&b);        if(a>b) swap(a,b);        lli ans = 0,l;        for(int j=1;j<=a;j=l+1){//分块加速            l= min(a/(a/j),b/(b/j));            ans += (lli)(sum[l]-sum[j-1])*(a/j)*(b/j);        }        printf("%lld\n",ans);    }    return 0;}
阅读全文
0 0
原创粉丝点击