bzoj2693--莫比乌斯反演+积性函数线性筛

推导:

设d=gcd(i,j)

利用莫比乌斯函数的性质

 

令sum(x,y)=(x*(x+1)/2)*(y*(y+1)/2)

令T=d*t

设f(T)=

T可以分块。又由于μ是积性函数,积性函数的约束和仍是积性函数,所以f也是积性函数,可以O(n)线性筛求得。总时间复杂度为

具体筛法看代码。

 代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define mod 100000009
#define _min(a,b) a>b?b:a
#define ll long long
inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    if(p1==p2){
        p2=(p1=buf)+fread(buf,1,100000,stdin);
        if(p1==p2)return EOF;
    }
    return *p1++;
}
inline void read(int& x){
    char c=nc();
    for(;c<'0'||c>'9';c=nc());
    for(x=0;c>='0'&&c<='9';x=x*10+c-48,c=nc());
}
int len;
char s[30];
inline void print(ll x){
    if(!x){
        putchar('0');putchar('\n');
        return;
    }
    for(len=0;x;x/=10)s[++len]=x%10;
    for(;len;len--)putchar(s[len]+48);
    putchar('\n');
}
inline int sum(ll x,ll y){
    return (x*(x+1)/2%mod)*(y*(y+1)/2%mod)%mod;
}
int T,i,j,k,n,m,ma,num,p[1000001],x,a[10001],b[10001],ans;
ll f[10000001];
bool v[10000001];
int main()
{
    read(T);
    for(i=1;i<=T;i++){
        read(a[i]);read(b[i]);
        if(a[i]>b[i]){k=a[i];a[i]=b[i];b[i]=k;}
        if(a[i]>ma)ma=a[i];
    }
    f[1]=1;
    for(i=2;i<=ma;i++){
        if(!v[i]){
            p[++num]=i;
            f[i]=-(1LL*i*(i-1)%mod);
        }
        for(j=1;j<=num&&p[j]*i<=ma;j++){
            v[p[j]*i]=1;
            if(i%p[j])f[i*p[j]]=f[i]*f[p[j]]%mod;else{
                f[i*p[j]]=f[i]*p[j]%mod;
                break;
            }
        }
    }
    for(i=2;i<=ma;i++)f[i]=(f[i]+f[i-1])%mod;
    for(k=1;k<=T;k++){
        ans=0;
        for(i=1;i<=a[k];i=j+1){
            j=_min(a[k]/(a[k]/i),b[k]/(b[k]/i));
            ans=(ans+(f[j]-f[i-1])*sum(a[k]/i,b[k]/i)%mod)%mod;
        }
        print((ans+mod)%mod);
    }
    return 0;
}
bzoj2693

 

posted @ 2016-12-14 21:19  gjghfd  阅读(317)  评论(0编辑  收藏  举报