HDU 5663 (莫比乌斯反演)

来源:互联网 发布:java报表 编辑:程序博客网 时间:2024/06/05 16:31

分析:

这道题就是一道公式推导题,我再来推一遍公式:

f(x)函数:

f(x)={1,0,x

ANS=n×mni=1mj=1f(gcd(i,j))这个时候只需要维护后面一块就可以了

TEST=i=1nj=1mf(gcd(i,j))=i=1nj=1md=gcd(i,j)f(d)=d=1min(n,m)f(d)i=1nj=1m(gcd(i,j)=d)=d=1min(n,m)f(d)i=1ndj=1md(gcd(i,j)=1)=d=1min(n,m)f(d)i=1ndj=1mdt|gcd(i,j)μ(t)=d=1min(n,m)f(d)t=1min(nd,md)μ(t)×ndt×mdt=g=1min(n,m)ng×mgd|gμ(d)×f(gd)使g=dt

这个时候就搞定了,后面一块gd|gμ(d)×f(gd)维护这个式子和,复杂度是o(nlogn)但是还可降低:gx2|gμ(x2)×f(gx2)xx2|gμ(d),这个时候复杂度就是o(n)(复杂度计算就是平方的倒数和,泰勒展开)。
然后维护gd|gμ(d)×f(gd)的前缀和,就可以分块做了,分块的复杂度o(n)

总的复杂度是o(n+Tn)

代码:

#include <cstdio>#include <cstdlib>#include <cmath>#include <cstring>#include <algorithm>#include <set>#include <map>#include <queue>#include <vector>#include <string>using namespace std;typedef long long LL;typedef vector <int>    VI;typedef pair <int,int>  PII;#define FOR(i,x,y)  for(int i = x;i < y;++ i)#define IFOR(i,x,y) for(int i = x;i > y;-- i)#define pb  push_back#define mp  make_pair#define fi  first#define se  second const int maxn = 10000010;int mu[maxn],prime[maxn];bool check[maxn];void Mobius(){    memset(check,false,sizeof(check));    prime[0] = 0;    mu[1] = 1;    FOR(i,2,maxn){        if(!check[i])   {mu[i] = -1;prime[++prime[0]] = i;}        FOR(j,1,prime[0]+1){            if(i*prime[j] > maxn)  break;            check[i*prime[j]] = true;            if(i% prime[j] == 0)    {mu[i*prime[j]] = 0;break;}            else    {mu[i*prime[j]] = -mu[i];}        }    }}LL sum[maxn];int n,m;LL calc(int x,int y){    LL ans = 0;    int i = 1;    while(i <= x){        int p = x/i,q = y/i;        int j = min(x/p,y/q);        ans += (LL)p*q*(sum[j]-sum[i-1]);        i = j+1;    }    return ans;}int main(){    Mobius();    memset(sum,0,sizeof(sum));    FOR(i,1,maxn){        int k = i*i;        if(k >= maxn)   break;        for(int j = k;j < maxn;j += k)  sum[j] += mu[j/k];    }    FOR(i,1,maxn)   sum[i] += sum[i-1];    int T;  scanf("%d",&T);    while(T--){        scanf("%d%d",&n,&m);        if(n < m)   swap(n,m);        printf("%I64d\n",(LL)n*m-calc(m,n));    }    return 0;}
0 0