[積性函數]DIVCNT2 - Counting Divisors (square)

http://www.spoj.com/problems/DIVCNT2/

sol:

考慮到i^2這個東西有點噁心
w(x)表示x的不同的質因子個數
d|i21=d|i2w(d) 實際上就是i的所有約數的質因子的冪是否加上i的對應質因子的冪,這樣就成爲了i^2的約數了。
考慮到2w(d) 的實際意義是1到d的無平方因子的個數。這個東西等價於
d|iq|dμ(q)2
這個東西就很有意思了,他長這樣
11μ2
(11)μ2
d(x)表示x的除數函數
就是dμ2
inq|iμ(q)2d(iq)
qnμ(q)2inqd(i)
2個東西預處理前1e6項,複雜度爲O(23)
對於前面那個當他的n很大的時候,可以這麼暴力算
iddi2μ(i)
實際上就是用1的倍數-1個質數的平方數+2個質數的平方數這樣容斥,容易注意到他的容斥係數和mu的定義一樣。
後面那個東西實際上就是
inni
當n很大的時候,暴力分塊也可以做到更號
直接暴力做是O(34)

#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
typedef double db;
int n,m;
inline int read()
{
    char c;
    int res,flag=0;
    while((c=getchar())>'9'||c<'0') if(c=='-')flag=1;
    res=c-'0';
    while((c=getchar())>='0'&&c<='9') res=(res<<3)+(res<<1)+c-'0';
    return flag?-res:res;
}
const int N=1e6+7;
const int M=1e6;
ll a[N],b[N];
int c[N],prime[N];
bool is[N];
inline ll calc1(int x)
{
    if(x<=M) return a[x];
    int y=sqrt(x);
    ll ans=0;
    for(int i=1;i<=y;++i)
        ans+=x/i/i*c[i];
    return ans;
}
inline ll calc2(int x)
{
    if(x<=M) return b[x];
    ll ans=0;
    int z,zz;
    for(int i=1;i<=x;++i)
    {
        z=x/i;
        zz=x/z;
        ans+=(zz-i+1)*z; 
        i=zz;
    }
    return ans;
} 
int main()
{
//  freopen("function.in","r",stdin);
//  freopen("function.out","w",stdout);
    n=1000000;
    b[1]=1;
    for(int i=2;i<=n;++i)
    for(int j=1;i*j<=n;++j)
    b[i*j]++;
    for(int i=2;i<=n;++i)
    {
        b[i]++;
        b[i]=b[i]+b[i-1];
    }
    c[1]=1;
    a[1]=1;
    for(int i=2;i<=n;++i)
    {
        if(!is[i]) prime[++prime[0]]=i,c[i]=-1;
        for(int j=1;j<=prime[0]&&i*prime[j]<=n;++j)
        {
            is[i*prime[j]]=1;
            if(!(i%prime[j]))
            {
                c[i*prime[j]]=0;
                break;
            }
            c[i*prime[j]]=-c[i];
        }
        a[i]=a[i-1]+(c[i]!=0);
    }
    m=read();
    while(m--)
    {
        n=read();
        int z,zz;
        ll ans=0;
        for(int i=1;i<=n;++i)
        {
            z=n/i;
            zz=n/z;
            ans+=(calc1(zz)-calc1(i-1))*calc2(z);
            i=zz;
        }
        printf("%lld\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章