SPOJ DIVCNT2

题目链接:
http://www.spoj.com/problems/DIVCNT2/

根据rzz的课件 可以分三段做

度教搞出来一种分一次做的方法 看起来很神的样子

#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define ll long long
char c;
inline void read(ll&a)
{a=0;do c=getchar();while(c<'0'||c>'9');while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();}
ll n;
const
    ll MAXN=(int)1e8+1;
mapMu,W,O;
int mu[MAXN],tot,prime[5761490],w[MAXN];
int cnt;
int D[2049];


inline ll m(ll x)
{
    return mu[x]==mu[x-1]?0:(D[w[x]-w[x-1]]&1?-1:1);
}

ll SolveMu(ll n)
{
    if(nreturn mu[n];
    if(Mu[n])return Mu[n];
    ll res=0;
    for(ll i=1;i*1ll*i<=n;i++)
        (res+=m(i)*(n/(i*i)));
    return Mu[n]=res;
}
ll SolveW(ll n)
{
    if(nreturn w[n];
    if(W[n])return W[n];
    ll res=0;
    ll i=1,j;
    while(i<=n)
    {
        j=n/(n/i);
        (res+=(SolveMu(j)-SolveMu(i-1))*1ll*((n/i)));
        i=j+1;
    }
    return W[n]=res;
}

ll SolveO(ll n)
{
    if(O[n])return O[n];
    ll res=0;
    ll i=1,j;
    while(i<=n)
    {
        j=n/(n/i);
        (res+=(SolveW(j)-SolveW(i-1))*1ll*((n/i)));
        i=j+1;
    }
    return O[n]=res;
}

void out(ll x)
{
    if(x<0)putchar('-'),x=-x;
    if(x>9)out(x/10);
    putchar('0'+x%10);
}

ll Up;
vectorQ;
int main()
{
    Up=-1;
    ll T;
    mu[1]=w[1]=1;
    read(T);
    while(T--)
    {
        ll n;
        read(n);
        Q.push_back(n);
        if(Up//out(SolveO(n));
        //puts("");
    }   
    Up=min(Up+1,MAXN);
    for(int i=2;iif(!w[i])prime[++tot]=i,mu[i]=-1,w[i]=2;
        for(int j=1,k;j<=tot&&(k=prime[j]*i)if(i%prime[j]==0)
            {mu[k]=0;w[k]=w[i];break;}
            mu[k]=-mu[i];w[k]=w[i]*2;
        }
        mu[i]=mu[i-1]+mu[i]*mu[i];
        w[i]+=w[i-1];
    }
    int j=1;
    for(int i=0;i<=11;j*=2,i++)D[j]=i;
    for(int i=0;iputs("");
    return 0;
} 

你可能感兴趣的:(杜教筛,数学)