zoukankan      html  css  js  c++  java
  • 莫比乌斯反演

    形式1

    已经有函数F(n)=∑  f(d),可以导出 f(n)=  ∑   μ(d)F(n/d)

                         d|n                            d|n

    形式2

    已经有F(n)∑   f(d),可以导出f(n)∑   μ(d/n)F(d)

                    n|d                           n|d

    bzoj2301 Problem b

    题目大意:求gcd(x,y)=k(a<=x<=b,c<=y<=d)的数对个数。

    思路:F(i)表示i|gcd(x,y)的数对个数,f(i)表示gcd(x,y)的数对个数,我们要求的就是f(k)。F(i)相对好求一些,F(i)=n/im/i⌋,

    f(i)=∑(i|a)μ(a/i)F(a)=∑(i|a)μ(a|i)n/am/a ,然后我们只需要枚举⌊n/am/a⌋的值就可以了(这个值据说是2(根n+根m)。我们穷举a

    找到所有⌊n/am/a相等的的位置(连续的),然后乘上预处理出来的mu函数的和就可以了。这里有一个小技巧,1...x的数列中,与n/i相等的值的最

    后一位是(n/(n/i)),这样我们找到n、m右边界较小的就是一段相等的区间了。

    同时,对于求一个区间内gcd=k的,我们可以通过将区间/k后找到互质的数对的个数就是答案了。

    再同时,对于这道题中的答案要容斥原理一下,每次都处理成[1...x][1...y],然后答案就是work(b,d)-work(a,d)-work(c,b)+work(a,c)了。

    这题中的技巧和化简思路都十分重要,这种穷举除数的思路据(某大神)说十分常用。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int mu[50010]={0},prime[50010]={0},k;
    bool flag[50010]={false};
    void prework(int n)
    {
        int i,j;
        mu[1]=1;
        for (i=2;i<=n;++i)
        {
            if (!flag[i])
            {
                prime[++prime[0]]=i;mu[i]=-1;
            }
            for (j=1;j<=prime[0]&&i*prime[j]<=n;++j)
            {
                flag[i*prime[j]]=true;
                if (i%prime[j]==0)
                {
                    mu[i*prime[j]]=0;break;
                }
                else mu[i*prime[j]]=-mu[i];
            }
        }
        for (i=1;i<=n;++i) mu[i]+=mu[i-1];
    }
    int work(int x,int y)
    {
        int i,last=0,ans=0;
        x/=k;y/=k;
        if (x>y) swap(x,y);
        for (i=1;i<=x;i=last+1)
        {
            last=min(x/(x/i),y/(y/i));
            ans+=(x/i)*(y/i)*(mu[last]-mu[i-1]);
        }
        return ans;
    }
    int main()
    {
        int n,a,b,c,d,i,ans;
        prework(50000);
        scanf("%d",&n);
        for (i=1;i<=n;++i)
        {
            scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
            ans=work(b,d)-work(a-1,d)-work(c-1,b)+work(a-1,c-1);
            printf("%d
    ",ans);
        }
    }
    View Code

    bzoj2818 GCD

    题目大意:求1~n中gcd(x,y)为素数的对数。

    思路:可以筛出素数,然后求出n/prime[i]内的gcd(x,y)=1的数对就可以了。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 10000005
    #define LL long long
    using namespace std;
    int prime[maxnode]={0},mu[maxnode]={0};
    bool flag[maxnode]={false};
    void shai(int n)
    {
        int i,j;mu[1]=1;
        for (i=2;i<=n;++i)
        {
            if (!flag[i]) {prime[++prime[0]]=i;mu[i]=-1;}
            for (j=1;j<=prime[0]&&prime[j]*i<=n;++j)
            {
                flag[prime[j]*i]=true;
                if (i%prime[j]==0){mu[i*prime[j]]=0;break;}
                else mu[i*prime[j]]=-mu[i];
            }
        }
        for (i=1;i<=n;++i) mu[i]+=mu[i-1];
    }
    LL work(int x)
    {
        int i,last;LL ans=0;
        for (i=1;i<=x;i=last+1)
        {
            last=x/(x/i);
            ans+=(LL)(x/i)*(LL)(x/i)*(LL)(mu[last]-mu[i-1]);
        }
        return ans;
    }
    int main()
    {
        int n,i,j;LL ans=0;
        scanf("%d",&n);shai(n);
        for (i=1;i<=prime[0];++i) ans+=work(n/prime[i]);
        printf("%I64d
    ",ans);
    }
    View Code

    当然也可以求一个phi的前缀和sum,然后1+2*sum[n/prime[i]],也是答案。

    bzoj3853GCD Array

    题目大意:在一个数列上进行操作。1)读入p,d,v,对所有gcd(i,p)=d的ai+v;2)求$sum_{i=1}^xa_i$.

    思路:听了题解才明白是反演。我们对于一次修改操作可以看作$a_i+=[gcd(i,p)=d]v$,对上式进行化简可以得到

    [gcd(i,p)=d]v=[gcd (frac{i}{d},frac{p}{d})=1]v

                      =vsum_{e|frac{i}{d},e| frac{p}{d} } mu{e}

                      = vsum_{ed|i,e|frac{p}{d}}mu{e}

                      =sum_{ed|i , e| frac{p}{d}} mu{e}v

    我们维护一个数组$f_e$,令$a_i=sum_{e|i}f_e$,修改的时候我们每次穷举$frac{p}{d}$的约数x(也就是e),x*d的位置加上x*v,用树状数组维护;查询的时候ANS=sum_{i=1}^xa_i

                  =sum_{i=1}^xsum_{e|i}f(e)

                   =sum_{i=1}^xleft lfloorfrac{x}{i} ight floor f(i)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define maxnode 200005
    using namespace std;
    long long cc[maxnode]={0};
    int n,prime[maxnode]={0},mu[maxnode]={0};
    vector<int> yue[maxnode];
    bool flag[maxnode]={false};
    void pre()
    {
        int i,j;
        mu[1]=1;
        for (i=2;i<maxnode;++i)
        {
            if (!flag[i])
            {
                prime[++prime[0]]=i;mu[i]=-1;
            }
            for (j=1;prime[j]*i<maxnode&&j<=prime[0];++j)
            {
                flag[prime[j]*i]=true;
                if (i%prime[j]) mu[i*prime[j]]=-mu[i];
                else
                {
                    mu[i*prime[j]]=0;break;
                }
            }
        }
    }
    void getyue()
    {
        int i,j;
        for (i=1;i<=maxnode;++i) yue[i].clear();
        for (i=1;i<maxnode;++i)
          for (j=i;j<maxnode;j+=i)
              yue[j].push_back(i);
    }
    int lowbit(int x){return x&(-x);}
    long long ask(int x,int y)
    {
        long long sum=0;
        --x;
        for (;y;y-=lowbit(y)) sum+=cc[y];
        for (;x;x-=lowbit(x)) sum-=cc[x];
        return sum;
    }
    void change(int x,int v)
    {
        for (;x<=n;x+=lowbit(x)) cc[x]+=(long long)v;
    }
    int main()
    {
        int m,i,j,p,v,d,op,ci=0;
        long long ans;
        pre();getyue();
        while(scanf("%d%d",&n,&m))
        {
          if (n==0&&m==0) break;
          memset(cc,0,sizeof(cc));++ci;
          printf("Case #%d:
    ",ci);
          for (i=1;i<=m;++i)
          {
            scanf("%d",&op);
            if (op==1)
            {
                scanf("%d%d%d",&p,&d,&v);
                if (p%d) continue;
                p=p/d;
                for (j=0;j<yue[p].size();++j) change(yue[p][j]*d,mu[yue[p][j]]*v);
            }
            else
            {
                scanf("%d",&p);ans=0;
                for (j=1;j<=p;j=d+1)
                {
                    d=(p/(p/j));
                    ans+=(long long)(p/j)*ask(j,d);
                }
                printf("%lld
    ",ans);
            }
          }
        }
    }
    View Code

    bzoj2005 noi2010能量采集

    题目大意:n×m的矩阵中,有n×m个点位于格点上,对于每个点,采集的能量是这个点和(0,0)连线上点的个数(不包含端点)×2+1,求采集所有点的能量和。

    思路:对于一个点(x,y),采集的能量是2×(gcd(x,y)-1)+1,求这个的sigma。可以用反演,穷举1~min(n,m)作为gcd的值,求出个数后乘i加起来乘2-1就是答案了。(反演的过程同第一题)。

            其实并不需要这么麻烦,我们在反演中F(d)表示d|gcd(x,y)的个数,F(d)=(n/d)(m/d),那么我们用这个数减去gcd=2d、3d……id的个数就可以了,用f(d)表示gcd=d的个数,就是用F(d)-f(2d)-f(3d)-……f(id),我们倒着穷举gcd,就可以完成了。不需要反演和求mu,速度还++。。。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxnode 100005
    #define up 100000
    using namespace std;
    int mu[maxnode]={0},prime[maxnode]={0};
    long long sum[maxnode]={0};
    bool flag[maxnode]={0};
    void getmu()
    {
        int i,j;
        mu[1]=1;
        for (i=2;i<=up;++i)
        {
            if (!flag[i])
            {
                prime[++prime[0]]=i;mu[i]=-1;
            }
            for (j=1;j<=prime[0]&&i*prime[j]<=up;++j)
            {
                flag[i*prime[j]]=true;
                if (i%prime[j]==0){mu[i*prime[j]]=0;break;}
                else mu[i*prime[j]]=-mu[i];
            }
        }
        for (i=1;i<=up;++i) sum[i]=sum[i-1]+(long long)mu[i];
    }
    long long ask(int n,int m,int k)
    {
        int i,j,last=0;
        long long ans=0;
        n/=k;m/=k;if (n>m) swap(n,m);
        for (i=1;i<=n;i=last+1)
        {
            last=min(n/(n/i),m/(m/i));
            ans+=(long long)(n/i)*(long long)(m/i)*(sum[last]-sum[i-1]);
        }
        return ans;
    }
    int main()
    {
        int n,m,i,j;
        long long ans=0;
        scanf("%d%d",&n,&m);
        if (n>m) swap(n,m);getmu();
        for (i=1;i<=n;++i) ans+=i*ask(n,m,i);
        ans=ans*2-(long long)n*(long long)m;
        printf("%I64d
    ",ans);
    }
    View Code

    在暑假跟着faebdc犇学习莫比乌斯反演,发现只需要记住两个式子,剩下的就是熟练转换了。

    sigma phi(d)=n                sigma mu(d)=e(n) ===>e(i)= (i==1 ? 1 : 0)

      d|n                                 d|n

    bzoj2154 Crash的数字表格

    题目大意:求sigma(i=1~n)sigma(j=1~m) lcm(i,j)

    思路;原式=sigma sigma i*j/gcd(i,j)

                   i=1~n j=1~m

                  =sigma sigma k1*k2*gcd(i,j) (设i=k1gcd(i,j),j=k2gcd(i,j),gcd(k1,k2)=1)

                   i=1~n j=1~m

                  =     sigma        d  sigma  sigma i*j*e(gcd(i,j))

                    d=1~min(n,m)   i=1~n/d j=1~m/d

                  =     sigma        d  sigma   sigma i*j sigma mu(k)

                    d=1~min(n,m)   i=1~n/d j=1~m/d  k|i&k|j

                  =     sigma        d         sigma            k^2 mu(k) sum(n/d/k,m/d/k)     sum(x,y)=sigma sigma i*j=(i*(i+1)/2)*(j*(j+1)/2)

                    d=1~min(n,m)    k=1~min(n/d,m/d)                                                              i=1~x j=1~y

    根号套根号的求出两个sigma,O(n)复杂度。(注意强转,i,j互质 <==> e(lca(i,j))=1)

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #include<cstdio>
    #define maxnode 10000005
    #define p 20101009
    #define LL long long
    using namespace std;
    int prime[maxnode]={0},mu[maxnode]={0};
    LL sum[maxnode]={0};
    bool flag[maxnode]={false};
    void shai(int n)
    {
        int i,j;
        mu[1]=1;
        for (i=2;i<=n;++i)
        {
            if (!flag[i])
            {
                prime[++prime[0]]=i;mu[i]=-1;
            }
            for (j=1;j<=prime[0]&&i*prime[j]<=n;++j)
            {
                flag[i*prime[j]]=true;
                if (i%prime[j]==0)
                {
                    mu[i*prime[j]]=0;break;
                }
                else mu[i*prime[j]]=-mu[i];
            }
        }
        for (i=1;i<=n;++i) sum[i]=(sum[i-1]+(((LL)mu[i]*(((LL)i*(LL)i)%p))%p+p)%p)%p;
    }
    LL getsum(LL *a,int l,int r)
    {
        --l;return ((a[r]-a[l])%p+p)%p;
    }
    LL get(int n,int m)
    {
        int i,last=0;LL ans=0;
        if (n>m) swap(n,m);
        for (i=1;i<=n;i=last+1)
        {
            last=min(n/(n/i),m/(m/i));
            LL xx=((LL)(n/i)*(LL)(n/i+1)/2%p)*((LL)(m/i)*(LL)(m/i+1)/2%p)%p;
            ans=(ans+getsum(sum,i,last)*xx%p)%p;
        }
        return (ans%p+p)%p;
    }
    LL work(int n,int m)
    {
        int i,last=0;LL ans=0;
        if (n>m) swap(n,m);
        for (i=1;i<=n;i=last+1)
        {
            last=min(n/(n/i),m/(m/i));
            ans=(ans+((LL)(last+i)*(LL)(last-i+1)/2%p)*get(n/i,m/i))%p;
        }
        return (ans%p+p)%p;
    }
    int main()
    {
        int n,m,i,j;
        scanf("%d%d",&n,&m);shai(max(n,m));
        printf("%lld",work(n,m));
    }
    View Code

    bzoj2671 Calc

    题目大意:求1~n中,(a+b)|ab的个数。

    思路:因为之前做过一道求ab=k(a+b)的问题,所以总想从这方面下手,但是思考了很久都没有进展。后来改变了一下思路,其实可以将式子都除去一个gcd(a,b),得到(x+y)|xygcd(a,b),因为gcd(x+y,x)=1,gcd(x+y,y)=1(orz sunshine),所以(x+y)|gcd(a,b),那么会给答案贡献n/(y*(x+y))(一)(这个式子是因为设gcd(a,b)=t(x+y),会有b=t(x+y)y<=n,所以有这么多个给答案。注意分母不为零!!!),其中gcd(x,y)=1,x<y,这里的y的上界是根n(因为gcd(a,b)*b<=n),所以我们枚举一下y,x可以n^(1/4)枚举,对于每一段(一)相等的段中,求出与y互质的数的个数,这里用到了容斥原理和莫比乌斯函数,一段区间[l,r]中与一个数n互质的数的个数是sigma(k|n)mu[k]*(r/k-(l-1)/k),所以就可以算出答案了。去网上找了一下这种做法的复杂度,暴力出奇迹吧。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define maxnode 100005
    #define LL long long
    using namespace std;
    int prime[maxnode]={0},mu[maxnode]={0},yue[maxnode*10]={0};
    bool flag[maxnode]={false};
    void shai(int n)
    {
        int i,j;mu[1]=1;
        for (i=2;i<n;++i){
            if (!flag[i]){prime[++prime[0]]=i;mu[i]=-1;}
            for (j=1;j<=prime[0]&&prime[j]*i<n;++j){
                flag[prime[j]*i]=true;
                if (i%prime[j])mu[i*prime[j]]=-mu[i];
                else{mu[i*prime[j]]=0;break;}
            }
        }
    }
    void fen(LL n)
    {
        LL i;yue[0]=0;
        for (i=1;i*i<=n;++i)
            if (n%i==0){
                yue[++yue[0]]=i;
                if (i*i!=n) yue[++yue[0]]=n/i;
            }
    }
    LL work(LL n)
    {
        LL a,b,l,r,i,j,up,last,ans=0;up=sqrt(n);
        for (b=1;b<=up;++b){
            fen(b);
            for (a=1;a<b&&b*(a+b)<=n;a=last+1){
                last=min(n/(n/(b*(a+b)))/b-b,b-1);
                for (i=1;i<=yue[0];++i)
                    ans+=n/(b*(a+b))*mu[yue[i]]*(last/yue[i]-(a-1)/yue[i]);
            }
        }return ans;
    }
    int main()
    {
        int n;scanf("%d",&n);shai(sqrt(n)+1);
        printf("%I64d
    ",work((LL)n));
    }
    View Code

    bzoj3994 约数个数和

    题目大意:设d(x)表示x的约数个数,求sigma(i=1~n)sigma(j=1~m)d(ij)

    思路:d(ij)=sigma(i|n)sigma(j|m)e(gcd(i,j))(考虑如果i、j不互质的时候可以通过质因数的变换使得互质,这样就导致多次计算了。)对这个式子反演。

      sigma(i=1~n)sigma(j=1~m)d(ij)=sigma(i=1~n)sigma(j=1~m)(n/i)(m/j)e(gcd(i,j))

                       =sigma(i=1~n)sigma(j=1~m)(n/i)(m/j)sigma(d|i&&d|j)mu(d)

                       =sigma(d=1~min(n,m))mu(d)gi(n/d)gi(m/d)      (gi(x)=sigma(i=1~x)(x/i),这一步可以设i=k1gcd(),j=k2gcd()                                                                                                                          考虑)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxm 50005
    #define LL long long
    using namespace std;
    int prime[maxm]={0},mu[maxm]={0};
    LL gi[maxm]={0};
    bool flag[maxm]={0};
    void shai(int n){
        int i,j;mu[1]=1;
        for (i=2;i<=n;++i){
            if (!flag[i]){prime[++prime[0]]=i;mu[i]=-1;}
            for (j=1;j<=prime[0]&&prime[j]*i<=n;++j){
                flag[prime[j]*i]=true;
                if (i%prime[j]) mu[i*prime[j]]=-mu[i];
                else{mu[i*prime[j]]=0;break;}
            }
        }for (i=2;i<=n;++i) mu[i]+=mu[i-1];
    }
    void pre(int n){
        int i,j,la;
        for (i=1;i<=n;++i)
            for (j=1;j<=i;j=la+1){
                la=i/(i/j);gi[i]+=(LL)(i/j)*(LL)(la-j+1);
            }
    }
    LL calc(int n,int m){
        int i,j,la;LL ans=0;
        if (n>m) swap(n,m);
        for (i=1;i<=n;i=la+1){
            la=min(n/(n/i),m/(m/i));
            ans+=(LL)(mu[la]-mu[i-1])*gi[n/i]*gi[m/i];
        }return ans;
    }
    int main(){
        int t,n,m;
        shai(maxm-1);pre(maxm-1);
        scanf("%d",&t);
        while(t--){
            scanf("%d%d",&n,&m);
            printf("%I64d
    ",calc(n,m));
        }
    }
    View Code

    bzoj3561 DZY Loves Math VI

    题目大意:求sigma(i=1~n)sigma(j=1~m) lcm(i,j)^gcd(i,j)。

    思路:sigma(i=1~n)sigma(j=1~m) lcm(i,j)^gcd(i,j)=sigma(i=1~n)sigma(j=1~m)[k1*k2*gcd(i,j)]^gcd(i,j)*e(gcd(k1,k2))

                              =sigma(d=1~min(n,m))d^d sigma(a=1~min(n/d,m/d)) a^(2d)*mu(a)g(n/d/a,m/d/a,d)

            设g(nn,mm,d)=sigma(i=1~nn)i^d * sigma(j=1~mm) j^d,这个数组可以用vector预处理,是nlnn的。

       做的时候暴力循环就可以了,复杂度是nlnn的。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #define N 500005
    #define p 1000000007LL
    #define LL long long
    using namespace std;
    vector<LL> sum[N];
    int prime[N]={0},mu[N];
    LL mi[N];
    bool flag[N]={false};
    void shai(){
        int i,j;mu[1]=1;
        for (i=2;i<N;++i){
            if (!flag[i]){
                prime[++prime[0]]=i;mu[i]=-1;
            }for (j=1;j<=prime[0]&&i*prime[j]<N;++j){
                flag[i*prime[j]]=true;
                if (i%prime[j]) mu[i*prime[j]]=-mu[i];
                else{mu[i*prime[j]]=0;break;}
            }
        }
    }
    LL getg(int x,int y,int d){return sum[d][x]*sum[d][y]%p;}
    LL getmi(LL x,int y){
        LL a=1LL;
        for (;y;y>>=1){
            if (y&1) a=a*x%p;
            x=x*x%p;
        }return a;}
    int main(){
        int i,j,n,m,up;LL ans=0LL,ci;
        scanf("%d%d",&n,&m);
        if (n>m) swap(n,m); shai();
        for (i=1;i<=m;++i){mi[i]=1LL;sum[i].push_back(0LL);}
        for (i=1;i<=m;++i)
            for (j=1;j*i<=m;++j){
                mi[j]=mi[j]*(LL)j%p;
                sum[i].push_back((sum[i][j-1]+mi[j])%p);
            }
        for (i=1;i<=m;++i) mi[i]=1LL;
        for (i=1;i<=n;++i){
            up=min(n/i,m/i);
            for (ci=0LL,j=1;j<=up;++j){
                mi[j]=mi[j]*(LL)j%p;
                ci=(ci+mi[j]*mi[j]%p*mu[j]*getg(n/i/j,m/i/j,i))%p;
            }ci=(ci%p+p)%p;
            ans=(ans+getmi((LL)i,i)*ci%p)%p;
        }printf("%I64d
    ",ans);
    }
    View Code

    bzoj4407 于神之怒加强版

    click here! 

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define N 5000005
    #define LL long long
    #define p 1000000007
    using namespace std;
    int k,prime[N]={0};
    LL gi[N]={0},ci[N];
    bool flag[N]={0};
    LL mi(LL x,int y){
        LL a=1LL;
        for(;y;y>>=1){
            if (y&1) a=a*x%p;
            x=x*x%p;
        }return a;}
    void shai(){
        int i,j,v;gi[1]=1;
        for (i=2;i<N;++i){
            if (!flag[i]){
                prime[++prime[0]]=i;
                ci[i]=mi((LL)i,k);
                gi[i]=((ci[i]-1LL)%p+p)%p;
            }for (j=1;j<=prime[0]&&i*prime[j]<N;++j){
                flag[v=i*prime[j]]=true;
                if (i%prime[j]) gi[v]=(gi[i]*(ci[prime[j]]-1)%p+p)%p;
                else{
                    gi[v]=gi[i]*ci[prime[j]]%p;
                    break;}
            }
        }for (i=2;i<N;++i) gi[i]=(gi[i]+gi[i-1])%p;}
    int main(){
        int t,n,m,i,j,up,last;LL ans;
        scanf("%d%d",&t,&k);shai();
        while(t--){
            scanf("%d%d",&n,&m);ans=0LL;
            for (up=min(n,m),i=1;i<=up;i=last+1){
                last=min(n/(n/i),m/(m/i));
                ans=(ans+(LL)(n/i)*(LL)(m/i)%p*((gi[last]-gi[i-1])%p+p)%p)%p;
            }printf("%I64d
    ",ans);
        }
    }
    View Code

    bzoj3529 数表

    click here!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100005
    #define LL long long
    #define p 2147483648LL
    using namespace std;
    struct use{int n,m,a,po;LL ans;}ai[N]={0};
    struct uu{LL v;int po;}fi[N]={0};
    LL ci[N]={0LL};
    int prime[N]={0},flag[N]={0},cnt[N]={0},mu[N]={0};
    int in(){
        int x=0;char ch=getchar();
        while(ch<'0'||ch>'9') ch=getchar();
        while(ch>='0'&&ch<='9'){
            x=x*10+ch-'0';ch=getchar();
        }return x;}
    LL mi(LL x,int y){
        if (!y) return 1LL;
        if (y==1) return x;
        LL mm=mi(x,y/2);
        if (y%2) return mm*mm*x;
        else return mm*mm;}
    void shai(){
        int i,j,x,y;LL xx;mu[1]=1;fi[1].v=1LL;
        for (i=1;i<N;++i) fi[i].po=i;
        for (i=2;i<N;++i){
            if (!flag[i]){
                mu[i]=-1;fi[i].v=(LL)i+1;
                prime[++prime[0]]=i;cnt[i]=1;
            }for (j=1;j<=prime[0]&&(x=i*prime[j])<N;++j){
                flag[x]=1;
                if (i%prime[j]){
                    fi[x].v=fi[i].v*(LL)(prime[j]+1);
                    mu[x]=-mu[i];cnt[x]=1;
                }else{
                    cnt[x]=cnt[i]+1;xx=mi(prime[j],cnt[x]);
                    fi[x].v=fi[i].v*(xx*(LL)prime[j]-1LL)/(xx-1LL);
                    mu[x]=0;}
            }
        }
    }
    int lowbit(int x){return x&(-x);}
    int cmp(const uu&x,const uu&y){return x.v<y.v;}
    int cmp1(const use&x,const use&y){return x.a<y.a;}
    int cmp2(const use&x,const use&y){return x.po<y.po;}
    void tch(int x,LL y){for (;x<N;x+=lowbit(x)) ci[x]=(ci[x]+y)%p;}
    void insert(int x){
        int i,j,y;y=fi[x].po;
        for (i=(N-1)/y;i;--i)
          if (mu[i]!=0) tch(i*y,(LL)mu[i]*fi[x].v);}
    LL ask(int x){
        LL sum=0LL;
        for (;x;x-=lowbit(x)) sum=(sum+ci[x])%p;
        return sum;}
    LL sig(int l,int r){return ((ask(r)-ask(l-1))%p+p)%p;}
    int main(){
        int t,i,j,x,y;t=in();shai();
        for (i=1;i<=t;++i){ai[i].n=in();ai[i].m=in();ai[i].a=in();ai[i].po=i;}
        sort(ai+1,ai+t+1,cmp1);
        sort(fi+1,fi+N,cmp);
        for (j=1,i=1;i<=t;++i){
            while(fi[j].v<=ai[i].a&&j<N) insert(j++);
            if (ai[i].n>ai[i].m) swap(ai[i].n,ai[i].m);
            for (x=1;x<=ai[i].n;x=y+1){
                y=min(ai[i].n/(ai[i].n/x),ai[i].m/(ai[i].m/x));
                ai[i].ans=(ai[i].ans+(LL)(ai[i].m/x)*(LL)(ai[i].n/x)%p*sig(x,y)%p)%p;
            }
        }sort(ai+1,ai+t+1,cmp2);
        for (i=1;i<=t;++i) printf("%I64d
    ",ai[i].ans);
    }
    View Code

    bzoj3309 DZY Loves Math

    click here!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 10000000
    #define LL long long
    using namespace std;
    int prime[N+1]={0},fi[N+1]={0};
    bool flag[N+1]={false};
    void dfs(int i,int k,int ci){
        if (i>prime[0]) return;
        if ((LL)ci*(LL)prime[i]>N) return;
        LL v=(LL)(ci*prime[i]);
        dfs(i+1,-k,ci*prime[i]);
        for (LL vv=v;vv<=N;vv*=v) fi[vv]=k;
        dfs(i+1,k,ci);}
    void shai(){
        int i,j,v;fi[0]=fi[1]=0;
        for (i=2;i<=N;++i){
            if (!flag[i]) prime[++prime[0]]=i;
            for (j=1;j<=prime[0]&&i*prime[j]<=N;++j){
                flag[v=i*prime[j]]=true;
                if (i%prime[j]==0) break;
            }
        }dfs(1,1,1);
        for (i=2;i<=N;++i) fi[i]+=fi[i-1];
    }
    int main(){
        int t,a,b,i,la;LL ans;
        shai();scanf("%d",&t);
        while(t--){
            scanf("%d%d",&a,&b);
            if (a>b) swap(a,b);
            for (ans=0LL,i=1;i<=a;i=la+1){
                la=min(a/(a/i),b/(b/i));
                ans+=(LL)(a/i)*(LL)(b/i)*(LL)(fi[la]-fi[i-1]);
            }printf("%I64d
    ",ans);
        }
    }
    View Code

    bzoj3202 项链

    click here!!!!

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 10000005
    #define LL long long
    #define pp 1000000007LL
    using namespace std;
    int prime[N]={0},mu[N],a,bi[N],az;
    LL inv,ai[N],n,ans,smu[N],p;
    bool flag[N]={false};
    void shai(){
        int i,j,v;mu[1]=1;smu[1]=1LL;
        for (i=2;i<N;++i){
            if (!flag[i]){prime[++prime[0]]=i;mu[i]=-1;}
            for (j=1;j<=prime[0]&&(v=i*prime[j])<N;++j){
                flag[v]=true;
                if (i%prime[j]) mu[v]=-mu[i];
                else{mu[v]=0;break;}
            }smu[i]=smu[i-1]+(LL)mu[i];
        }
    }
    LL mul(LL x,LL y){
        LL aa=0LL;x=(x%p+p)%p;y=(y%p+p)%p;
        if (y>x) swap(x,y);
        for (;y;y>>=1LL){
            if (y&1LL) aa=(aa+x)%p;
            x=(x+x)%p;
        }return aa;}
    LL mi(LL x,LL y){
        LL aa=1LL;x=(x%p+p)%p;
        for (;y;y>>=1LL){
            if (y&1LL) aa=mul(aa,x)%p;
            x=mul(x,x)%p;
        }return aa;}
    LL getc(LL x){return mul(mul(mul(x,x+1LL),(x+2LL)),inv);}
    LL calc(){
        LL an=0LL;int i,la;
        for (i=1;i<=a;i=la+1){
            la=a/(a/i);
            an=(an+mul(smu[la]-smu[i-1],getc((LL)(a/i))))%p;
        }return (an%p+p)%p;}
    LL getf(LL nn,LL x){
        return ((mi(x-1LL,nn)+(nn%2LL ? -1LL : 1LL)*(x-1LL)%p)%p+p)%p;
    }
    void dfs(int i,LL x,LL y,LL z){
        if (i==az+1){
            ans=((ans+mul(getf(n/x,z),y))%p+p)%p;
            return;
        }int j;LL cc=1LL;dfs(i+1,x,y,z);
        for (j=1;j<=bi[i];++j){
            cc*=ai[i];
            dfs(i+1,x*cc,y*(cc/ai[i]*(ai[i]-1LL)),z);
        }
    }
    int main(){
        LL x;int t,i;
        shai();scanf("%d",&t);
        while(t--){
            scanf("%I64d%d",&n,&a);az=0;
            for (x=n,i=1;i<=prime[0]&&x>1LL;++i)
                if (x%(LL)prime[i]==0LL){
                    ai[++az]=(LL)prime[i];bi[az]=0;
                    while(x%(LL)prime[i]==0LL){++bi[az];x/=(LL)prime[i];}
                }
            if (x>1){ai[++az]=x;bi[az]=1;}
            if (n%pp==0LL) p=pp*pp;
            else p=pp;
            inv=mi(6LL,pp*(pp-1LL)-1LL);
            x=calc();ans=0LL;dfs(1,1LL,1LL,x);
            if (n%pp==0LL){p=pp;ans=ans/p%p*mi(n/p,p-2LL)%p;}
            else ans=mul(ans,mi(n,p-2LL));
            printf("%I64d
    ",ans);
        }
    }
    View Code
  • 相关阅读:
    [转]对Lucene PhraseQuery的slop的理解
    Best jQuery Plugins of 2010
    15 jQuery Plugins To Create A User Friendly Tooltip
    Lucene:基于Java的全文检索引擎简介
    9 Powerful jQuery File Upload Plugins
    Coding Best Practices Using DateTime in the .NET Framework
    Best Image Croppers ready to use for web developers
    28 jQuery Zoom Plugins Creating Stunning Image Effect
    VS2005 + VSS2005 实现团队开发、源代码管理、版本控制(转)
    禁止状态栏显示超链
  • 原文地址:https://www.cnblogs.com/Rivendell/p/4555669.html
Copyright © 2011-2022 走看看