Orz w_yqts
Orz xudyh
杜教筛模板题
给定积性函数f(x)
函数s(x)为f(x)的前缀和
f(x)满足Σf(d)=g(x),d为x的约数,g(x)的前缀和可以在较短时间内算出.
求s(n)
从枚举约数到枚举倍数,将离散变为连续…
上面的j枚举的就是倍数,i是当前倍数可以支持的约数,不难发现,可以支持的约数是连续的.
预处理前n^(2/3),后面直接用map记忆化…
大概是O(n^(2/3))的吧…
PS:这道题我预处理前2500000就过了,别的都TLE了…
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define N 2500005
map <int,ll> f1,f2;
ll phi[N],miu[N];
int pn,pr[N],flag[N];
inline void init()
{
flag[1]=phi[1]=miu[1]=1LL;
pn=0;
for (int i=2;i<N;++i)
{
if (!flag[i]) pr[++pn]=i,phi[i]=i-1,miu[i]=-1;
for (int j=1;j<=pn && pr[j]*i<N;++j)
{
flag[i*pr[j]]=1;
if (i%pr[j]==0) {phi[i*pr[j]]=phi[i]*pr[j];miu[i*pr[j]]=0;break;}
phi[i*pr[j]]=phi[i]*(pr[j]-1);miu[i*pr[j]]=-miu[i];
}
}
for (int i=1;i<N;++i) phi[i]+=phi[i-1],miu[i]+=miu[i-1];
}
inline ll calcphi(ll n)
{
if (n<N) return phi[n];
if (f1[n]) return f1[n];
ll res=(ll)(n+1)*n>>1;
for (ll i=2,pos;i<=n;i=pos+1)
{
pos=n/(n/i);
res-=calcphi(n/i)*(pos-i+1);
}
return f1[n]=res;
}
inline ll calcmiu(ll n)
{
if (n<N) return miu[n];
if (f2[n]) return f2[n];
ll res=1LL;
for (ll i=2,pos;i<=n;i=pos+1)
{
pos=n/(n/i);
res-=calcmiu(n/i)*(pos-i+1);
}
return f2[n]=res;
}
void solve()
{
int n;
scanf("%d",&n);
printf("%lld %lld\n",calcphi(n),calcmiu(n));
}
int main()
{
init();
int T;
cin>>T;
while (T--) solve();
return 0;
}