hdu 4746 Mophues (莫比乌斯反演 + 分块+线性筛)

来源:互联网 发布:三维设计软件 编辑:程序博客网 时间:2024/06/05 08:19

注意:

因为是多组询问(5000)而n又高达5e5,所以我们每次的时间一定要控制在logn或sqrt(n)内才能1s过,分块是必须的了。

然后是一个坑点:必须在线性筛里统计数量,自己写函数一个个统计会t在这上。

跟csu 1325的思路类似:需要预处理出 Fi 的系数,然后求前缀和分块。然而这题p的值会影响某些Fi 的系数,所以我们需要将不同的p值的前缀和分别保存下来。注意此题当p大于19时,最小值也是1e6,所以直接输出m*n就好。我们预处理p从0到19的前缀和,注意到当p很大时,所有的fi 都会被统计到 Fi 中,所以我们从小到大处理就好。第二个代码的预处理思路类似,然而可能是由于局部性原理的原因,慢了100ms左右。
http://blog.csdn.net/wing_wuchen/article/details/76861929

249ms的代码:

#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 = 5e5+20;bool isprime[maxn];//int phi[maxn];int prime[maxn],miu[maxn];int cnt[maxn];void moblus(){    int num = 0;miu[1] = 1;    for(lli i = 2;i < maxn;i++){        if(!isprime[i]){            prime[num++] = i,miu[i] = -1;//phi[i] = i-1;            cnt[i] = 1;        }        for(lli j = 0;j < num && i*prime[j] < maxn;j++){            lli x = prime[j];            isprime[i*x] = 1;cnt[i*x] = cnt[i]+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];bool v[maxn];int sum[25][maxn];int main(){    moblus();    for(int p = 0;p <= 19;p++){        for(int i = 1;i < maxn;i++){            if(cnt[i] > p || v[i]) continue;            v[i] = true;            for(int j = 1;j*i < maxn;j++){                ff[i*j] += miu[j];            }        }        for(int i = 1;i < maxn;i++){            sum[p][i] = sum[p][i-1]+ff[i];        }    }    int q,n,m,p;    scanf("%d",&q);    while(q--){        scanf("%d%d%d",&n,&m,&p);        if(p > 19){            printf("%lld\n",(lli)m*(lli)n);            continue;        }        if(n>m) swap(n,m);        lli ans = 0,l;        for(int i = 1;i <= n;i=l+1){            l = min(n/(n/i),m/(m/i));            ans += (lli)(sum[p][l]-sum[p][i-1])*(lli)(n/i)*(lli)(m/i);        }        printf("%lld\n",ans);    }    return 0;}

390ms的代码:

#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 = 5e5+20;bool isprime[maxn];//int phi[maxn];int prime[maxn],miu[maxn];int cnt[maxn];void moblus(){    int num = 0;miu[1] = 1;    for(lli i = 2;i < maxn;i++){        if(!isprime[i]){            prime[num++] = i,miu[i] = -1;//phi[i] = i-1;            cnt[i] = 1;        }        for(lli j = 0;j < num && i*prime[j] < maxn;j++){            lli x = prime[j];            isprime[i*x] = 1;cnt[i*x] = cnt[i]+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 sum[25][maxn];int main(){    moblus();    for(int i = 1;i < maxn;i++){        for(int j = 1;j*i < maxn;j++){            sum[cnt[i]][i*j] += miu[j];//我觉得可能是这里 内存的局部性原理导致100ms的延迟吧        }    }    for(int i = 1;i < maxn;i++){        sum[0][i] = sum[0][i-1]+sum[0][i];    }    for(int p = 1;p <= 19;p++){        for(int i = 1;i < maxn;i++){            sum[p][i] = sum[p][i-1] + sum[p][i];        }        for(int i = 1;i < maxn;i++){            sum[p][i] += sum[p-1][i];        }    }    int q,n,m,p;    scanf("%d",&q);    while(q--){        scanf("%d%d%d",&n,&m,&p);        if(p > 19){            printf("%lld\n",(lli)m*(lli)n);            continue;        }        if(n>m) swap(n,m);        lli ans = 0,l;        for(int i = 1;i <= n;i=l+1){            l = min(n/(n/i),m/(m/i));            ans += (lli)(sum[p][l]-sum[p][i-1])*(lli)(n/i)*(lli)(m/i);        }        printf("%lld\n",ans);    }    return 0;}
阅读全文
0 0
原创粉丝点击