ZOJ The Sum of Unitary Totient (Min_25筛)
作者:互联网
题意: 给你一个函数f(n)=(p1a1-1)(p2a2-1)...(prar-1) ,n=p1a1p2a2...prar 求\[\sum\limits_{i = 1}^n {f(i)} \],\[n < = 1e9\]
思路: \[f(p) = p - 1,f({p^k}) = {p^k} - 1\],直接用min_25筛就可以了,按道理来讲我感觉min_25筛是稳过的,但我交了几十次才过,要不是在网上看到有人用min_25筛过了我还以为我想错了
#include<bits/stdc++.h> #define ms(x) memset(x,0,sizeof(x)) #define sws ios::sync_with_stdio(false) using namespace std; typedef long long ll; const int maxn=8e4+5; const ll mod=1e9+7; int id1[maxn],id2[maxn]; int w[maxn]; int vis[maxn]; int prime[maxn]; ll sup[maxn]; int tot; int sqr; int cnt; ll g[maxn]; int h[maxn]; ll n; int k; inline ll S(int x,int y){ if(x<=1||prime[y] > x) return 0; k=x<=sqr?id1[x]:id2[n/x]; register ll ans=1ll*(g[k]-h[k]-(sup[y-1]-y+1)); for(register int i=y;i<=tot&&1ll*prime[i]*prime[i]<=x;++i){ register ll pk1=1ll*prime[i],pk2=pk1*prime[i]; for(;pk2<=x;pk1=pk2,pk2=pk2*prime[i]){ ans+=(pk1-1)*S(x/pk1,i+1)+pk2-1; } } return ans; } int upper; int main(){ tot=0; register int i,j; for( i=2;i<maxn;++i){ if(!vis[i]){ prime[++tot]=i; sup[tot]=sup[tot-1]+i; } for(j=1;j<=tot&&i*prime[j]<maxn;++j){ vis[i*prime[j]]=1; if(i%prime[j]==0){ break; } } } while(~scanf("%lld",&n)){ cnt=0; upper=n; sqr=sqrt(upper); for(i=1;i<=upper;i=j+1){ j=upper/(upper/i); w[++cnt]=upper/i; if(w[cnt]<=sqr) id1[w[cnt]]=cnt; else id2[j]=cnt; g[cnt]=1ll*w[cnt]*(w[cnt]+1)/2-1; h[cnt]=w[cnt]-1; } register int x; for(j=1;j<=tot&&1ll*prime[j]*prime[j]<=upper;++j)if(h[j]!=h[j-1]||g[j]!=g[j-1]){ for(i=1;i<=cnt&&1ll*prime[j]*prime[j]<=w[i];++i){ x=w[i]/prime[j]; k=x<=sqr?id1[x]:id2[n/x]; g[i]-=(prime[j])*(g[k]-(sup[j-1])); h[i]-=(h[k]-(j-1)); } } printf("%lld\n",S(n,1)+1); } return 0; }
标签:25,Unitary,const,Min,int,ll,min,maxn 来源: https://www.cnblogs.com/azznaz/p/11517872.html