zoukankan      html  css  js  c++  java
  • BZOJ 2693: jzptab [莫比乌斯反演 线性筛]

    2693: jzptab

    Time Limit: 10 Sec  Memory Limit: 512 MB
    Submit: 1194  Solved: 455
    [Submit][Status][Discuss]

    Description

    Input

    一个正整数T表示数据组数

    接下来T行 每行两个正整数 表示N、M

    Output

    T行 每行一个整数 表示第i组数据的结果

    Sample Input

    1

    4 5

    Sample Output

    122
    HINT
    T <= 10000
    N, M<=10000000

    和上题一样,不过多组数据
    利用了和bzoj2820类似的技巧D=di 改变求和指标,这样就可以把Sum提前,剩下的部分处理前缀和
     
    如何处理前缀和:
    积性函数的约数和也是积性函数,可以用线性筛
    g[i]=约数和D*i*mu[i]
    显然g[p]=p*(1-p)
    g[i*p[j]] 当p[j]|i时  mu[ii]中ii带有p[j]的话就是0了不能计入,所以p[j]只能在剩下的一块里,也就是只有D变了,所以总的就是p[j]*g[i]
     
    尝试了一下枚举倍数的方法,T了
     
    总结:其实这两道题和gcd=k的个数两道题很像,都是第一题只要求一个,第二题要求多个,然后就要改写式子然后处理前缀和......
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=1e7+5,MOD=100000009;
    inline int read() {
        char c=getchar();
        int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int n,m;
    bool notp[N];int p[N];
    ll s[N],mu[N],g[N];
    void sieve(){
        mu[1]=1;
        g[1]=1;
        for(int i=2;i<N;i++){
            if(!notp[i]) p[++p[0]]=i,mu[i]=-1,g[i]=i-(ll)i*i;
            for(int j=1;j<=p[0]&&i*p[j]<N;j++){
                int t=i*p[j];
                notp[t]=1;
                if(i%p[j]==0){
                    mu[t]=0;
                    g[t]=(g[i]*p[j])%MOD;
                    break;
                }
                mu[t]=-mu[i];
                g[t]=(g[i]*g[p[j]])%MOD;
            }
        }
        
        for(int i=1;i<N;i++) g[i]=(g[i]+g[i-1])%MOD;    
    
    }
    inline ll S(ll x,ll y){
        return ((x*(x+1)/2)%MOD)*((y*(y+1)/2)%MOD)%MOD;
    }
    int main(){
        sieve();
        int T=read();
        while(T--){
            n=read();
            m=read();
            if(n>m) swap(n,m);
            ll ans=0,r=0;
            for(ll D=1;D<=n;D=r+1){
                r=min(n/(n/D),m/(m/D));
                ans=(ans+S(n/D,m/D)*(g[r]-g[D-1]))%MOD;
            }
            printf("%lld
    ",(ans+MOD)%MOD);
        }
    }
     
  • 相关阅读:
    第二次结对编程作业
    团队项目-需求分析报告
    团队项目-选题报告
    第一次结对编程作业
    第一次个人编程作业
    第一次博客作业
    第04组 团队Git现场编程实战
    第二次结对编程作业
    团队项目-需求分析报告
    团队项目-选题报告
  • 原文地址:https://www.cnblogs.com/candy99/p/6216145.html
Copyright © 2011-2022 走看看