bzoj 3944 Sum

转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents

题意

求欧拉函数和莫比乌斯函数的前缀和,数据范围  2311

思路

这个题就是之前做过的51Nod 1239(求欧拉函数前缀和) 和 51Nod 1244(求莫比乌斯函数前缀和)合起来
这两个题的题解分别在这里和这里
个人还是很喜欢51Nod这样的oj,会每组数据都分别给运行时间,也可以获得数据,感觉bzoj给的运行时间很迷。。


具体代码如下:
Result:Accepted     Memory:29952 KB     Time :1687 ms

#include
const int maxn = 5e6;//maxn = n^(2/3)
using namespace std;
typedef long long ll;
const int HASH_MOD=2e5;
int mu[maxn];
bool vis[maxn];
int p[maxn];
ll phi[maxn];
ll n;
struct Hash{
    ll key[HASH_MOD], val[HASH_MOD];
    int head[HASH_MOD], nxt[HASH_MOD];
    int tot;
    void init(){
        memset(head, -1, sizeof(head));
        tot = 0;
    }
    ll inst(ll x, ll y){
        int k = x % HASH_MOD;
        key[tot] = x;
        val[tot] = y;
        nxt[tot] = head[k];
        head[k] = tot++;
    }
    ll finda(ll x){
        int k = x % HASH_MOD;
        for(int i = head[k]; i != -1; i = nxt[i])
            if(key[i] == x)
                return val[i];
        return -1;
    }
}hs,hs2;
void Linear_Shaker()
{
    phi[1]=1;mu[1]=1;
    for(int i=2;iif(!vis[i])
        {
            phi[i]=i-1;
            mu[i]=-1;
            p[++p[0]]=i;
        }
        for(int j=1;p[j]*i1;
            if(i%p[j]==0)
            {
                phi[p[j]*i]=phi[i]*p[j];
                mu[p[j]*i]=0;
                break;
            }
            phi[p[j]*i]=phi[i]*(p[j]-1);
            mu[p[j]*i]=-mu[i];
        }
    }
    for(int i=1;i1];
        mu[i]+=mu[i-1];
    }
}
ll calcmu(ll x)
{
    if (xreturn mu[x];
    int y = hs.finda(x);
    if(y!= -1)
        return y;
    ll ans = 1;
    for(ll l=2,r; l<=x; l=r+1)
    {
        r=x/(x/l);
        ans-=calcmu(x/l)*(r-l+1);
    }
    hs.inst(x,ans);
    return ans;
}
ll calcphi(ll x)
{
    if (xreturn phi[x];
    ll y = hs2.finda(x);
    if(y!= -1)
        return y;
    ll ans = x*(x+1)/2;
    for(ll l=2,r; l<=x; l=r+1)
    {
        r=x/(x/l);
        ans-=calcphi(x/l)*((r-l+1));
    }
    hs2.inst(x,ans);
    return ans;
}
int main()
{
    Linear_Shaker();
    int T;
    scanf("%d",&T);
    while(T--)
    {
        hs.init();
        hs2.init();
        scanf("%lld",&n);
        printf("%lld %lld\n",calcphi(n),calcmu(n));
    }
    return 0;
}

你可能感兴趣的:(数论,莫比乌斯反演,杜教筛)