BZOJ 3994 Sum

Posted on 2017-03-02 20:27  ziliuziliu  阅读(79)  评论(0编辑  收藏  举报

orz我还以为要卡很久的常数。。。2333 10s给我过了。。。

对这道题可以挂链表,可能比map快吧。。

#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1000050
#define mod 999983
using namespace std;
int t,n,tot=0,miu[maxn*5],prime[maxn*5],tot1=0,g1[maxn],g2[maxn],tot2=0;
bool vis[maxn*5];
long long phi[maxn*5];
struct link
{
    int nxt,id;
    long long val;
}l1[maxn],l2[maxn];
void get_table()
{
    miu[1]=1;phi[1]=1;
    for (int i=2;i<=5000000;i++)
    {
        if (!vis[i])
        {
            phi[i]=i-1;miu[i]=-1;
            prime[++tot]=i;
        }
        for (int j=1;j<=tot && i*prime[j]<=5000000;j++)
        {
            vis[i*prime[j]]=true;
            if (i%prime[j]) {miu[i*prime[j]]=-miu[i];phi[i*prime[j]]=phi[i]*(prime[j]-1);}
            else {miu[i*prime[j]]=0;phi[i*prime[j]]=phi[i]*prime[j];break;}
        }
    }
    for (int i=1;i<=5000000;i++) phi[i]+=phi[i-1],miu[i]+=miu[i-1];
}
int find(int num,int pos,int type)
{
    int now=(type==1)?g1[num]:g2[num];
    while (now)
    {
        if (type==1)
        {
            if (l1[now].id==pos) return now;
            else now=l1[now].nxt;
        }
        else
        {
            if (l2[now].id==pos) return now;
            else now=l2[now].nxt;
        }
    }
    return 0;
}
void add(int now,int pos,long long val,int type)
{
     if (type==1)
     {
         l1[++tot1].id=pos;l1[tot1].val=val;
         l1[tot1].nxt=g1[now];g1[now]=tot1;
     }
     else
     {
         l2[++tot2].id=pos;l2[tot2].val=val;
         l2[tot2].nxt=g2[now];g2[now]=tot2;
     }
}
long long get_phi(long long x)
{
    if (x<=5000000) return phi[x];
    long long reg=find(x%mod,x,1);if (reg) return l1[reg].val;
    long long ret=x*(x+1)/2,l=2,r;
    while (l<=x)
    {
        r=x/(x/l);
        ret-=get_phi(x/l)*(r-l+1);
        l=r+1;
    }
    add(x%mod,x,ret,1);
    return ret;
}
int get_miu(long long x)
{
    if (x<=5000000) return miu[x];
    long long reg=find(x%mod,x,2);if (reg) return l2[reg].val;
    long long ret=1,l=2,r;
    while (l<=x)
    {
        r=x/(x/l);
        ret-=get_miu(x/l)*(r-l+1);
        l=r+1;
    }
    add(x%mod,x,ret,2);
    return ret;
}
int main()
{
    scanf("%d",&t);get_table();
    for (int i=1;i<=t;i++)
    {
        scanf("%lld",&n);
        printf("%lld %d\n",get_phi(n),get_miu(n));
    }
    return 0;
}