ZOJ The Sum of Unitary Totient

版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/qq_35950004/article/details/85097851

ZOJ 3808

%%%唐老师杜教筛博客课后练习题
不过网上好像没题解啊,好像唐老师也是分段打表的…
但是可以Min_25筛

显然这个 ϕ \phi^* 是积性函数,
ϕ ( p ) = p 1 \phi^*(p) = p-1
ϕ ( p k ) = p k 1 \phi^*(p^k) = p^k-1
然后好像就完了,稳稳的Min_25筛套路,不要用什么map记忆化,Min_25筛这个东西由于是二维的状态,分分钟MLE,分段存还要多个log,还不如不存快,目前4400ms稳居倒数第一,希望大家让我这个倒数第一更有含金量一点.

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
using namespace std;

int n,sn,id;
int h[maxn],a[maxn],pr[maxn],cnt_pr,sh[maxn];
LL g[maxn],sg[maxn];
inline int ID(int a){ return a <= sn ? a : id - n/a + 1; }
void sieve()
{
	sn = sqrt(n);
	id = cnt_pr = 0;
	for(int i=1;i<=n;i++) 
		a[++id] = i = (n / (n / i)),
		g[id] = 1ll * i * (i+1) / 2 - 1,
		h[id] = i - 1;
	for(int i=1;i<=sn;i++)
		if(h[i]!=h[i-1])
		{
			pr[++cnt_pr] = i , sg[cnt_pr] = sg[cnt_pr-1]+i,sh[cnt_pr] = sh[cnt_pr-1] + 1;
			for(int j=id,lim=i*i;a[j]>=lim;j--)
				g[j] -= i * (g[ID(a[j]/i)] - sg[cnt_pr-1]),
				h[j] -= h[ID(a[j]/i)] - sh[cnt_pr-1];
		}
}

map<int,LL>mp[maxn];

LL S(int a,int b)
{
	if(a < pr[b]) 
		return 0;
	//if(mp[b].count(a)) return mp[b][a];
	LL ret = (g[ID(a)] - h[ID(a)]) - (sg[b-1] - sh[b-1]);
	for(int i=b;i<=cnt_pr && pr[i]*pr[i]<=a;i++)
		for(int x=pr[i];1ll*x*pr[i]<=a;)
			ret += S(a/x,i+1)*(x-1),
			ret += (x=x*pr[i])-1;
	return ret;
}

int main()
{
	//freopen("1.in","r",stdin);
	for(;~scanf("%d",&n);)
	{
		sieve();
		printf("%lld\n",S(n,1)+1);
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35950004/article/details/85097851
ZOJ
sum